用技术创造价值,用艺术塑造自我!
Posts tagged ibatis
Ibatis3功能一览
Apr 27th
ibatis3的设计相对ibatis2来说改动较大,可以说是在功能和配置继承的基础上翻天覆地的修改,所以:你别指望2个版本是自动兼容的。暴露了更多底层的接口和添加Dynamic SQL的功能提升了其拓展性,但是添加Annotation的功能却是鸡肋。相关的功能点我们还是看看这张图先。
新功能点
1:Dynamic SQL:动态SQL对熟悉JSTL或基于xml的文本处理的程序员来说是很好理解的,采用了基于OGNL的表达式后更是让XML mapper的配置减少到原来的一半。示例代码如下:
<select id=”findActiveBlogWithTitleLike” parameterType=”Blog” resultType=”Blog”>
SELECT * FROM BLOG
WHERE state = ‘ACTIVE’
<if test=”title != null”>
AND title like #{title}
</if>
</select>
2:Maper Annotations:这个功能比较鸡肋,至少偶是这样认为。程序员在代码中写sql,这个给人的感觉是回到了jdbc的环境中,而且 Annotaciton和java代码高度耦合了,并非配置优先。
3:SelectBuilder:用java代码来写sql,它使用static import和ThreadLocal变量的方式来保证语法的简介,很容易的去处理交织的条件和SQL格式化。
public String selectBlogsSql() {
BEGIN(); // Clears ThreadLocal variable
SELECT("*");
FROM("BLOG");
return SQL();
}
表达的结果是:select * from blog;
4:暴露底层接口:ibatis可以通过实现一些接口来拦截执行某些特定的功能点,默认情况下有4种:
* Executor(update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
* ParameterHandler(getParameterObject, setParameters)
* ResultSetHandler(handleResultSets, handleOutputParameters)
* StatementHandler(prepare, parameterize, batch, update, query)
具体的实例请看:ibatis user guide
对入门者的建议:
- 当然需要先了解sql map的配置情况,每个标签的一些属性,尤其是需要使用<sql>这个标签来减少sql的重复;
- 特定的情况实现 TypeHandler这个接口,例如java的对象中的enum对象和数据库字段的对应。oracle数据库的blob字段可以直接找到默认实现 BlobTypeHnadler就好了;
- 尽量不要用ibator这个自动工具来生成dao层的代码,这样代码的可维护性过差,但是可以研究下生成的代码;
- 了解一些setting的属性,特定功能打开和关闭特定配置。例如cache功能。
一些问题:
- 如果你想把ibatis3用到项目中,最好点击这里看看是否有你不能接受的bug吧!
- 缺少spring框架的集成支持,估计还是需要自己写plugs和spring等框架集成或搜集非官方的文档。
- 网上资料不全,遇到问题只能跟代码了!
资源:
spring+ibatis 批量提交数据提升性能
Feb 27th
在系统中,提取数据循环计算后,每次需要有大概3000条左右的数据需要提交到数据库。以前在循环中单条插入,开始只有200条左右的数据,看不出性能上的问题,现在数据量增长了很多,所以需要对提交功能做一下优化。spring集成了ibatis的批量提交的功能,我们只要调用API就可以了
首先在你的dao中需要继承org.springframework.orm.ibatis.support.SqlMapClientDaoSupport
然后在代码中调用getSqlMapClientTemplate方法, 覆写SqlMapClientCallback类中的doInSqlMapClient的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public void insertCreditItemBatch(final List<credititem></credititem> creditItemList) throws DataAccessException{ this.getSqlMapClientTemplate().execute(new SqlMapClientCallback(){ public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException { executor.startBatch(); int batch = 0; for(CreditItem creditItem:creditItemList){ //调用获取sequence的方法。如果没有的话就去掉这行代码。 creditItem.setCreditItemId(getNextId()); //参数1为:ibatis中需要执行的语句的id executor.insert("CreditItem_insertCreditItem", creditItem); batch++; //每500条批量提交一次。 if(batch==500){ executor.executeBatch(); batch = 0; } } executor.executeBatch(); return null; } }); } |
批量插入减少了获取数据库连接池的次数,经过测试可以提高60%到70%的性能,大家不妨在项目中使用一下。
ibatis的延迟加载机制
Oct 29th
在Domain Moudel中,经常会碰到一个域对象中包含另外一个域对象的列表,例如:一个blog的文章会有多个回复。我们就拿blog来做实例说明,情形一:获取blog的文章信息展示给用户,此内容只包括Article对象的信息;情形二:获取单个文章Article的信息,包括用户对这个文章的回复信息。
//文章对象 Article
public class Article{
public String articleId;
public String title;
public String content;
public String userId;
public Date createTime;
public List<Review> reviewList;//Review域对象list
……//其他属性,get,set方法;
}
//回复对象 Review
public class Review{
public String reviewId;
public String title;
public String content;
public String articleId;
public String userId;
……//其他属性,get,set方法;
}
ibatis的一对多的配置文件如下:
<sqlMap namespace=”Article”>
<typeAlias alias=”article” type=”com.ibatis.eg.Article”/>
<typeAlias alias=”review” type=”com.ibatis.eg.Review”/>
<resultMap id=”article_result” class=”article”>
<result property=”articleId” column=”articleId”/>
<result property=”title” column=”title”/>
<result property=”content” column=”content”/>
<result property=”userId” column=”userId”/>
<result property=”createTime” column=”createTime”/>
<result property=”review” column=”articleId” select = “getReviewByArticleId”/>
……
</resultMap>
<select id=”findArticle” resultMap=”article_result” parameterClass=”article”>
SELECT
articleId,
content,
……
FROM article
<dynamic prepend=”where”>
<isNotEmpty prepend=”and” property = “articleId”>
articleId = #articleId#
</isNotEmpty>
<isNotEmpty prepend=”and” property = “content”>
content = #content#
</isNotEmpty>
……
</dynamic>
</select>
<!–此处的resultClass的类和数据库中的字段需要保持一致,否则需要 as 一下或者在此文件中配置一个resultMap–>
<!–例如:如果数据库中是review_Id需要 select review_Id as reviewId ……–>
<select id=”getReviewByArticleId” resultClass=”review” parameterClass=”String”>
SELECT
reviewId,
articleId,
content,
……
FROM review where articleId = #articleId#
</select>
</sqlMap>
如果我们要实现延迟加载(lazy loadding)的功能,仅仅配置上述xml文件还是不够的,在ibatis的主配置文件sql-map-config.xml中,需要把ibatis的两项配置做一下修改。
<settings
……
lazyLoadingEnabled=”true”
enhancementEnabled=”true”
……/>
lazyLoadingEnabled设置系统是否实现延迟加载机制,enhancementEnabled设置是否用字节码强制机制,通过字节码强制机制可以为lazy loadding带来性能方面的改进;当用户 getSqlMapClientTemplate().queryForList(”findArticle”,article)的时候,实际上只是执行了查询article表的信息,而在Article对象中getReview()的时候,才会执行后面的查询Review对象的语句;这样在首页访问Article列表的时候就不用加载Review的信息,而在点击单个文章(Article)浏览的时候需要回复对象Review的时候,则会执行getReviewByArticleId的查询操作,把列表信息给出来。这样做明显的减少了代码的负责程度,按需提取信息也提升了系统的性能!
如果是settings中配置useStatementNamespaces = “true”(是否使用Statement命名空间)的话,上面的xml配置resultMap中的延迟加载信息应该写成:select = “Article.getReviewByArticleId”,同时dao中也要写成:getSqlMapClientTemplate().queryForList(”Article.findArticle”,article);
下面是做一下简单的测试代码:
public void testListLazyLoading() {
ArticleDao articleDao = (ArticleDao) this.getApplicationContext().getBean(”articleDao”);
Article article = new Article();
article.setArticleId(”00000005″);
List<Article> list = articleDao.listLazyLoading(article);
for (int i = 0; i < list.size(); i++) {
Article articleTmp = (Article) list.get(i);
//List<Review> reviewList = articleTmp.getReviewList();
System.out.println(i + “———ArticleId=” + articleTmp.getArticleId());
//for(Review review:reviewList){
//System.out.println( “———reviewId=” + review.getReviewId());
//}
}
}
执行上面测试语句的时候,仅仅查询acticle表,只有去掉注释的时候,才会把review表中的信息查询出来。
参考资料:
1:夏昕 xiaxin(at)gmail.com ibatis开发指南
2:Clinton Begin iBATIS SQL Maps2
3:Owen Cline DB2 UDB、WebSphere 和 iBATIS
卓望java工程师郭经干对完成本文亦有贡献!原创文章,转载请注明原文地址!

