在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工程师郭经干对完成本文亦有贡献!原创文章,转载请注明原文地址!