【Ibatis】(十三)、复杂类型属性(即自定义类型的属性)

来源:互联网 发布:python 模 编辑:程序博客网 时间:2024/06/10 13:58

复杂类型用以表示在数据库中相互关系为一对一,一对多的数据。

映射文件:

Xml代码  收藏代码
  1. <!--complex type property that defined by user-->  
  2.         <resultMap id="get-product-complex" class="product">  
  3.             <result property="id" column="prd_id"/>  
  4.             <result property="description" column="prd_description"/>  
  5.             <result property="price" column="prd_price"/>  
  6.             <result property="category" column="prd_cat_id" select="getCategory-complex"/>  
  7.         </resultMap>  
  8.         <resultMap id="get-category-complex" class="category">  
  9.             <result property="id" column="cat_id"/>  
  10.             <result property="description" column="cat_description"/>  
  11.         </resultMap>    
  12.         <select id="getCategory-complex" resultMap="get-category-complex">  
  13.             <![CDATA[ 
  14.                 select * from t_category where cat_id = #value#  
  15.             ]]>  
  16.         </select>  
  17.         <select id="getProduct-complex" resultMap="get-product-complex" parameterClass="java.lang.Integer">  
  18.             <![CDATA[ 
  19.                 select * from t_product where prd_id = #value# 
  20.             ]]>  
  21.         </select>   
  22.         <!--END-->  

 DAO层:

Java代码  收藏代码
  1. public Product getProductUseComplexType(int id) throws SQLException {  
  2.         init();  
  3.         Product product = (Product)sqlMapClient.queryForObject("getProduct-complex", id);  
  4.         return product;  
  5.     }  

 Test类:

Java代码  收藏代码
  1. /** 
  2.      * 测试复杂属性类型 
  3.      * @throws SQLException 
  4.      */  
  5.     public void getProductUseComplexType() throws SQLException{  
  6.         Product product = productDao.getProductUseComplexType(1);  
  7.         System.out.println(product);  
  8.     }  

 结果:

id:1
description:basketball
price206.99
catId:1
catDescription:sports

 

上面的例子中,Product对象拥有一个类型为Category的category属性。因为category是复杂类型(用户定义的类型),JDBC不知道如何给它赋值。通过将category属性值和另一个mapped statement联系起来,为SQL Map引擎如何给它赋值提供了足够的信息。通过执行“getProduct”,“get-product-result”Result Map使用PRD_CAT_ID字段的值去调用“getCategory”。“get-category-result”Result Map将初始化一个Category对象并赋值给它。然后整个Category对象将赋值给Product的category属性。

 

避免N+1 Select(1:1) 
上面的方法存在一个问题,就是无论何时加载一个Product,实际上都要执行两个SQL语句(分别加载Product和Category)。只加载一个Product的情况下,这个问题似乎微不足道。但在执行一个获得10个Product的查询时,每得到一个Product都要分别执行一个加载Category的SQL语句。结果共执行了11次查询:一次用于得到一个Product List,每得到一个Product对象都要执行另外一次查询,以获得相应的Category对象(N+1,这个例子是10+1=11)。
解决方法是,使用一个联合查询和嵌套的属性映射来代替两个查询statement。

映射文件:

Xml代码  收藏代码
  1. <!--avoid N+1 select(1:1)-->  
  2.         <resultMap id="get-product-complex-promotion" class="product">  
  3.             <result property="id" column="PRD_ID"/>  
  4.             <result property="description" column="PRD_DESCRIPTION"/>  
  5.             <result property="price" column="prd_price"/>  
  6.             <result property="category.id" column="CAT_ID" />  
  7.             <result property="category.description" column="CAT_DESCRIPTION" />  
  8.         </resultMap>  
  9.         <statement id="getProduct-complex-promotion" parameterClass="int" resultMap="get-product-complex-promotion">  
  10.         <![CDATA[ 
  11.             select * from t_product, t_category 
  12.             where prd_cat_id=cat_id 
  13.             and prd_id = #value# 
  14.         ]]>  
  15.         </statement>  

 DAO层:

Java代码  收藏代码
  1. public Product getProductUseComplexTypePromotion(int id)  
  2.             throws SQLException {  
  3.         init();  
  4.         Product product = (Product)sqlMapClient.queryForObject("getProduct-complex-promotion", id);  
  5.         return product;  
  6.     }  

 Test类:

Java代码  收藏代码
  1. /** 
  2.      * 测试复杂属性类型的改进(避免N+1 select) 
  3.      * @throws SQLException 
  4.      */  
  5.     public void getProductUseComplexTypePromotion() throws SQLException{  
  6.         Product product = productDao.getProductUseComplexType(1);  
  7.         System.out.println(product);  
  8.     }  

 结果和上面的一样。

 

延迟加载 VS 联合查询(1:1) 
必须要声明的是,使用联合查询的方案并不总是最好的。假如很少有必要访问相关的对象(如Product对象的Category属性),则不用联合查询加载所有的Categor属性可能更快。对于牵涉到外部连接或没有索引字段的数据库设计时,更是如此。在这种情况下,使用延迟加载和字节码增强选项的子查询,可能性能会更好。基本的原则是,如果您需要访问相关的对象,则使用联合查询。否则,使用延迟加载和字节码增强选项的子查询。 
如果您不知道选择哪种方法,别担心。您可以随时更改选择而不会影响到Java代码。上面两个例子都得到相同的结果,并使用同样的调用方法。唯一要考虑的是,如果您要缓存查询结果,则使用子查询(而不是联合查询)来缓存查询结果。


原创粉丝点击