mybaties之关联查询与延迟加载
来源:互联网 发布:sor文件打开软件 编辑:程序博客网 时间:2024/05/16 07:05
一Mybaties关联查询与缓存
基本数据模型:
如上所示是我们电商系统的基本数据模型
1.1 一对一映射
模拟一个订单只能属于一个用户的,一对一映射。
SELECT orders.`id`, orders.`user_id`, orders.`number`, user.`username`, user.`sex`FROM orders, USERWHERE orders.`user_id` = user.`id`
1.1.1 以resultType作为扩展类
创建可扩展的PO类,扩展订单实体:
publicclass OrdersExt extends Orders{ //添加用户属性 /*USER.username, USER.address */ private String username; private String address; public String getUsername() { returnusername; } publicvoid setUsername(String username) { this.username = username; } public String getAddress() { returnaddress; } publicvoid setAddress(String address) { this.address = address; } }
创建mapper映射接口:
public List<OrdersExt> findOrdersUser();
创建映射文件:
<mapper namespace="cn.itcast.mybatis.mapper.OrdersMapper"> <!-- 定义查询订单表列名的SQL片段 --> <sql id="select_orders"> Orders.id, Orders.user_id, orders.number, orders.createtime, orders.note </sql> <!-- 定义查询用户表列名的SQL片段 --> <sql id="select_user"> user.username, user.address </sql> <!-- 进行订单信息查询,包括用户的名称和地址信息 --> <select id="findOrdersUser" resultType="OrdersExt"> Select <include refid="select_orders"/> <include refid="select_user"></include> from orders,user where orders.user_id = user.id </select></mapper>
加载映射文件
<!-- 批量加载mapper文件,需要mapper接口文件和mapper映射文件名称相同且在同一个包下 --><package name="cn.itcast.mybatis.mapper"/>
测试代码
@Testpublicvoid testFindOrdersUser(){ // 创建sqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); // 通过SqlSession构造usermapper的代理对象 OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class); // 调用usermapper的方法 List<OrdersExt> list = ordersMapper.findOrdersUser(); System.out.println(list); // 释放SqlSession sqlSession.close();}
1.1.2 以resultMap作为扩展
vo实体类
publicclass Orders { private Integer id; private Integer userId; private String number; private Date createtime;private String note;private User user;
mapper接口:
public List<OrdersExt> findOrdersUserRstMap();<!-- 进行订单信息查询,包括用户的名称和地址信息 (ResultMap)--> <select id="findOrdersUserRstMap" resultMap="OrdersUserRstMap"> Select <include refid="select_orders"/> , <include refid="select_user"></include> from orders,user where orders.user_id = user.id
xml映射文件
</select> <!-- 定义orderUserResultMap --> <resultMap type=" cn.itcast.mybatis.po.Orders" id="OrdersUserRstMap"> <id column="id"property="id" /> <result column="user_id"property="userId" /> <result column="number"property="number" /> <result column="createtime"property="createtime" /> <result column="note"property="note" /> <!-- 映射一对一关联关系的用户对象--> <!-- property:指定关联对象要映射到Orders的哪个属性上 javaType:指定关联对象所要映射的java类型 --> <!-- id标签:指定关联对象结果集的唯一标识,很重要,不写不会报错,但是会影响性能 --> <association property="user"javaType="cn.itcast.mybatis.po.User"> <id column="user_id"property="id" /> <result column="username"property="username" /> <result column="address"property="address" /> </association> </resultMap>
测试代码
@Testpublicvoid testFindOrdersUserRstMap() { // 创建sqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); // 通过SqlSession构造usermapper的代理对象 OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class); // 调用usermapper的方法 List<Orders> list = ordersMapper.findOrdersUserRstMap(); //此处我们采用debug模式来跟踪代码,然后验证结果集是否正确 System.out.println(list); // 释放SqlSession sqlSession.close
resultType:使用resultType实现较为简单,如果pojo中没有包括查询出来的列名,需要增加列名对应的属性,即可完成映射。
如果没有查询结果的特殊要求建议使用resultType。
resultMap:需要单独定义resultMap,实现有点麻烦,如果对查询结果有特殊的要求,使用resultMap可以完成将关联查询映射pojo的对象属性中。
resultMap可以实现延迟加载,resultType无法实现延迟加载。
1.2 一对多映射
业务场景描述:一个订单有多个订单明细。
Select Orders.id, Orders.user_id, orders.number,orders.createtime,orders.note,user.username,user.address,orderdetail.iddetail_id,orderdetail.items_id,orderdetail.items_numfrom orders,user,orderdetailwhere orders.user_id = user.id andorders.id = orderdetail.orders_id
修改订单实体
在Orders类中添加以下属性,并提供get/set方法:
//订单明细private List<Orderdetail> detailList;
mapper接口
// 查询订单信息及订单明细信息(一对多映射之使用resultMap)public List<Orders> findOrdersAndOrderdetailRstMap();
编写映射文件Mapper.xml
<!-- 定义OrdersAndOrderdetailRstMap --><!-- extends:继承已有的ResultMap,值为继承的ResultMap的唯一标示 --><resultMap type="Orders"id="OrdersAndOrderdetailRstMap" extends="OrdersUserRstMap"> <!-- 映射关联关系(一对多) --> <!-- collection标签:定义一个一对多关系 ofType:指定该集合参数所映射的类型 --> <collection property="detailList"ofType="Orderdetail"> <id column="detail_id"property="id" /> <result column="items_id"property="itemsId" /> <result column="items_num"property="itemsNum" /> </collection> </resultMap> <!-- 查询订单信息,包括用户名称、用户地址,订单商品信息(嵌套结果) --><select id="findOrdersAndOrderdetailRstMap"resultMap="OrdersAndOrderdetailRstMap"> Select <include refid="select_orders"/>, <include refid="select_user"/>, orderdetail.id detail_id, orderdetail.items_id, orderdetail.items_num from orders,user,orderdetail where orders.user_id = user.id and orders.id = orderdetail.orders_id </select>
resultMap的extends属性:可以用此属性来继承一个已有的resultmap。但是它继承的resultMap的type和它本身的type要保持一致。通过resultmap的继承,可以减少mapper的冗余映射。
测试代码
@Testpublicvoid testFindOrdersAndOrderdetailRstMap() { // 创建sqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); // 通过SqlSession构造usermapper的代理对象 OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class); // 调用usermapper的方法 List<Orders> list = ordersMapper.findOrdersAndOrderdetailRstMap(); //此处我们采用debug模式来跟踪代码,然后验证结果集是否正确 System.out.println(list); // 释放SqlSession sqlSession.close();
mybatis使用resultMap的collection对关联查询的多条记录映射到一个list集合属性中。
1.3 多对多映射
用户信息与商品信息的多对多关系
select Orders.id, Orders.user_id, orders.number,orders.createtime,orders.note,user.username,user.address,orderdetail.iddetail_id,orderdetail.items_id,orderdetail.items_num items.name items_name, items.detail items_detail FROM orders,USER, orderdetail, itemsWHERE user.`id` = orders.`user_id` ANDorders.`id` = orderdetail.`orders_id` ANDorderdetail.`items_id` = items.`id`
修改实体信息,分别在用户中添加订单信息,订单中添加订单明细,订单明细中添加订单项
在user类中添加List<Orders> ordersList 属性
// 订单信息private List<Orders> ordersList;
在Orders类中添加List<Orderdetail>属性
//订单明细private List<Orderdetail> detailList;
在Orderdetail类中添加Items属性
//商品信息private Items items;
接口定义
//查询用户及用户购买商品信息(多对多映射之使用resultMap)public List<User> findUserAndItemsRstMap();
编写映射文件
<!-- 定义UserAndItemsRstMap --> <resultMap type="User" id="UserAndItemsRstMap"> <!-- 用户信息 --> <!-- id:关联查询用户的唯一标示 --> <id column="user_id"property="id" /> <result column="username"property="username" /> <result column="address"property="address" /> <!-- 订单信息(一个用户有多个订单) --> <collection property="ordersList"ofType="orders"> <id column="id"property="id" /> <result column="user_id"property="userId" /> <result column="number"property="number" /> <result column="createtime"property="createtime" /> <result column="note"property="note" /> <!-- 订单明细信息(一个订单有多个订单明细) --> <collection property="detailList"ofType="orderdetail"> <id column="detail_id"property="id" /> <result column="items_id"property="itemsId" /> <result column="items_num"property="itemsNum" /> <!-- 商品信息(一个订单明细对应一个商品) --> <association property="items"javaType="cn.itcast.mybatis.po.Items"> <id column="items_id"property="id" /> <result column="items_name"property="name" /> <result column="items_detail"property="detail" /> </association> </collection> </collection> </resultMap> <!-- 查询用户及用户购买商品信息(多对多映射之使用resultMap) --> <select id="findUserAndItemsRstMap" resultMap="UserAndItemsRstMap"> Select <include refid="select_orders"/> , <include refid="select_user"/> , <include refid="select_orderdetail"></include> , items.name items_name, items.detail items_detail from orders,user,orderdetail,items where orders.user_id = user.id and orders.id = orderdetail.orders_id and orderdetail.items_id = items.id </select>
编写测试代码:
@Test publicvoid testFindUserAndItemsRstMap() { // 创建sqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); // 通过SqlSession构造usermapper的代理对象 OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class); // 调用usermapper的方法 List<User> list = ordersMapper.findUserAndItemsRstMap(); // 此处我们采用debug模式来跟踪代码,然后验证结果集是否正确 System.out.println(list); // 释放SqlSession sqlSession.close(); }
1.3.1 关联映射总结
resultType:
作用:将查询结果按照sql列名pojo属性名一致性映射到pojo中。
场合:常见一些明细记录的展示,比如用户购买商品明细,将关联查询信息全部展示在页面时,此时可直接使用resultType将每一条记录映射到pojo中,在前端页面遍历list(list中是pojo)即可。
resultMap:使用association和collection完成一对一和一对多高级映射(对结果有特殊的映射要求)。
association:
作用:将关联查询信息映射到一个pojo对象中。
场合:为了方便查询关联信息可以使用association将关联订单信息映射为用户对象的pojo属性中,比如:查询订单及关联用户信息。
使用resultType无法将查询结果映射到pojo对象的pojo属性中,根据对结果集查询遍历的需要选择使用resultType还是resultMap。
collection:
作用:将关联查询信息映射到一个list集合中。
场合:为了方便查询遍历关联信息可以使用collection将关联信息映射到list集合中,比如:查询用户权限范围模块及模块下的菜单,可使用collection将模块映射到模块list中,将菜单列表映射到模块对象的菜单list属性中,这样的作的目的也是方便对查询结果集进行遍历查询。
如果使用resultType无法将查询结果映射到list集合中。
1.4 延迟加载
resultMap中的association和collection标签具有延迟加载的功能。
延迟加载的意思是说,在关联查询时,利用延迟加载,先加载主信息。需要关联信息时再去按需加载关联信息。这样会大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
Mybatis默认是不开启延迟加载功能的,我们需要手动开启。
需要在SqlMapConfig.xml文件中,在<settings>标签中开启延迟加载功能。
lazyLoadingEnabled、aggressiveLazyLoading
<settings> <!-- 开启延迟加载,默认是false --> <setting name="lazyLoadingEnabled"value="true"/> <!--积极的懒加载模式,默认是false--> <setting name="aggressiveLazyLoading"value="false"/></settings>
<!-- 定义OrdersUserLazyLoadingRstMap --><resultMap type="cn.itcast.mybatis.po.Orders"id="OrdersUserLazyLoadingRstMap"> <id column="id" property="id"/> <result column="user_id" property="userId"/> <result column="number" property="number"/> <result column="createtime" property="createtime" /> <result column="note" property="note"/> <!-- 延迟加载用户信息 --> <!-- select:指定延迟加载需要执行的statement的id(是根据user_id查询用户信息的statement) 我们使用UserMapper.xml中的findUserById完成根据用户ID(user_id)查询用户信息 如果findUserById不在本mapper中,前边需要加namespace --> <!-- column:主信息表中需要关联查询的列,此处是user_id --> <association property="user" select="cn.itcast.mybatis.mapper.UserMapper.findUserById"column="user_id"></association></resultMap> <!-- 查询订单信息,延迟加载关联查询的用户信息 --><select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User"> SELECT * FROM user WHERE id = #{id}</select>
如上图所示通过懒加载关联查询用户信息。
映射文件
<package name="cn.itcast.mybatis.mapper"/>
查询订单信息
// 查询订单信息,延迟加载关联查询的用户信息public List<Orders> findOrdersUserLazyLoading();