三、MyBatis系列:Mapper 映射 之 关联对象属性及延迟加载

在开发时,经常有这种需求,我拿到了一个order表单实体时,我需要知道该表单是属于哪个用户的。
这时访问 order.getUser() 获取用户信息,这时应该得到一个用户的信息实例。
解决这个问题的方法有三种:
1、通过1条SQL语句进行关联查询,同时读取表单和用户信息;
2、同时发送2条SQL,用于读取 order 与 user信息;
3、先用1条SQL读取order表单信息,访问getUser()时再用另1个SQL读取user信息;
 
实体定义如下:
 1 public class User {
 2     private Integer id;
 3     private String username;
 4     private Date birthday;
 5     private String sex;
 6     private String address;
 7 }
 8 public class Order {
 9     private int id;
10     private User user;
11     private int number;
12     private Date createtime;
13     private String note;
14 }

第一种方法:使用关联查询的 mapper 的配置

 1 <resultMap type="cn.xleos.mybatis.po.Order" id="orderUserMap">
 2     <id property="id" column="orders_id" />
 3     <result property="createtime" column="orders_createtime" />
 4     <result property="number" column="orders_number" />
 5     <result property="note" column="orders_note" />
 6     <association property="user" javaType="cn.xleos.mybatis.po.User">
 7         <id property="id" column="user_id" />
 8         <result property="username" column="user_username" />
 9         <result property="birthday" column="user_birthday" />
10         <result property="sex" column="user_sex" />
11         <result property="address" column="user_address" />
12     </association>
13 </resultMap>
14 <select id="getOrdersAndUser">
15     SELECT
16     orders.id AS orders_id,
17     orders.number AS orders_number,
18     orders.createtime AS orders_createtime,
19     orders.note AS orders_note,
20     `user`.id AS user_id,
21     `user`.username AS user_username,
22     `user`.birthday AS user_birthday,
23     `user`.sex AS user_sex,
24     `user`.address AS user_address
25     FROM orders
26     INNER JOIN `user` ON `user`.id = orders.user_id
27 </select>

第二种方法,使用二条SQL语句来完成读取表单与用户信息

在读取order关联时 association 节使用了 select="getUserById" 属性,它表示使用 getUserById 这个SQL来读取用户信息。

 1 <resultMap type="cn.xleos.mybatis.po.Order" id="orderMap">
 2     <id property="id" column="id" />
 3     <result property="createtime" column="createtime" />
 4     <result property="number" column="number" />
 5     <result property="note" column="note" />
 6     <association property="user" column="user_id"
 7         javaType="cn.xleos.mybatis.po.User" select="getUserById" />
 8 </resultMap>
 9 <select id="getOrders" resultMap="orderMap">
10     SELECT id, user_id, number, createtime, note, FROM orders
11 </select>
12 <select id="getUserById" parameterMap="int" resultType="cn.xleos.mybatis.po.User">
13     SELECT id, username, birthday, sex, address FROM user where id = #{value}
14 </select>

编写一个单元测试,通过断步来看看MyBatis是如何提交SQL至数据库的。

 1 @Test
 2 public void getOrdersTest() {
 3     SqlSession sqlSession = sqlSessionFactory.openSession();
 4     try {
 5         System.out.println("1. 读取 order 表单数据对象. ");
 6         Order order = sqlSession.selectOne("test.getOrders", 3);
 7         System.out.println("2. 访问表单的 user 属性. ");
 8         User user = order.getUser();
 9         System.out.println(user);
10     } finally {
11         sqlSession.close();
12     }
13 }

以下是日志输出:

 1 DEBUG [main] - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
 2 DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
 3 1. 读取 order 表单数据对象. 
 4 DEBUG [main] - Opening JDBC Connection
 5 DEBUG [main] - Created connection 2063763486.
 6 DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@7b02881e]
 7 DEBUG [main] - ==>  Preparing: SELECT id, user_id, number, createtime, note FROM orders WHERE id = ? 
 8 DEBUG [main] - ==> Parameters: 3(Integer)
 9 DEBUG [main] - ====>  Preparing: SELECT id, username, birthday, sex, address FROM user where id = ? 
10 DEBUG [main] - ====> Parameters: 1(Integer)
11 DEBUG [main] - <====      Total: 1
12 DEBUG [main] - <==      Total: 1
13 2. 访问表单的 user 属性. 
14 User [id=1, username=王五, birthday=Thu Jul 10 00:00:00 CST 2014, sex=2, address=北京市
15 DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@7b02881e]
16 DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@7b02881e]
17 DEBUG [main] - Returned connection 2063763486 to pool.

通过日志可以发生在读取 order 数据时,就同时发送了2条SQL语句至数据库,读取 order 与 user 数据。

第三种方法,使用延时加载来访问 getUser() 时使用SQL语句读取user信息

1、需要在全局配置文件中添加lazyLoadingEnabled=true;
2、在关联映射(association)中设置 fetchType="lazy" 属性;
3、其它均与第二种方法一致;

1 <resultMap type="cn.xleos.mybatis.po.Order" id="orderMap">
2     <!-- 省略其它属性映射 -->
3     <association property="user" column="user_id"
4         javaType="cn.xleos.mybatis.po.User" select="getUserById" fetchType="lazy" />
5 </resultMap>

也编写一个单元测试,通过断步来看看MyBatis是如何提交SQL至数据库的。

 1 @Test
 2 public void getOrdersLazyTest() {
 3     SqlSession sqlSession = sqlSessionFactory.openSession();
 4     try {
 5         System.out.println("1. 读取 order 表单数据对象. ");
 6         Order order = sqlSession.selectOne("test.getOrders", 3);
 7         System.out.println("2. 访问表单的 user 属性. ");
 8         User user = order.getUser();
 9         System.out.println(user);
10     } finally {
11         sqlSession.close();
12     }
13 }

以下是日志输出:

 1 DEBUG [main] - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
 2 DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
 3 1. 读取 order 表单数据对象. 
 4 DEBUG [main] - Opening JDBC Connection
 5 DEBUG [main] - Created connection 1071097621.
 6 DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3fd7a715]
 7 DEBUG [main] - ==>  Preparing: SELECT id, user_id, number, createtime, note FROM orders WHERE id = ? 
 8 DEBUG [main] - ==> Parameters: 3(Integer)
 9 DEBUG [main] - <==      Total: 1
10 2. 访问表单的 user 属性. 
11 DEBUG [main] - ==>  Preparing: SELECT id, username, birthday, sex, address FROM user where id = ? 
12 DEBUG [main] - ==> Parameters: 1(Integer)
13 DEBUG [main] - <==      Total: 1
14 User [id=1, username=王五, birthday=Thu Jul 10 00:00:00 CST 2014, sex=2, address=北京市
15 DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3fd7a715]
16 DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@3fd7a715]
17 DEBUG [main] - Returned connection 1071097621 to pool.

使用了延时加载后,在读取 order 表单时仅发送一个SQL语句,于数据库查询出 order 对象; 在访问 order.getUser() 时,再发送一条SQL至数据库,读取出 user 记录;

posted @ 2015-06-28 19:34  夏亮  阅读(1496)  评论(0编辑  收藏  举报