MyBatis高级结果映射(一对一、一对多、多对多的映射),延迟加载,查询缓存(一级缓存),二级缓存的学习记录;
1、学习中所使用到的例子,数据库基础分析
2、高级结果映射
3、延迟加载
4、一级缓存
5、二级缓存
1、学习中所使用到的例子,数据库基础分析
2、高级结果映射
resultType与resultMap:
resultType来进行结果映射,数据库中查询几条记录,那么在resultType就会映射成几条记录;resultType映射是一个平铺式的映射; resultMap比较繁琐一些,是一种层级式映射,在企业中如果没有特殊要求,一般使用的都是resultType来完成一对一的映射; resultType实现查询机制,需要自定义pojo,pojo属性名和sql查询的列名是一致的;企业开发中的resultType简单方便便于使用 resultMap可以将sql查询结果信息中的部分属性映射到一个pojo中;需要的是映射配置;并且如果有查询到其他表中的内容首先要进行的是实体类关系的分析,以及映射关系的分析,并且分清一对一,一对多,多对多的关系;
下面的例子中会使用上述的购物车的数据库结构创建表,并且生成实体po类,进行操作(代码只会贴出关键代码块);
例子1:订单信息与用户信息
使用实体PO类:
OrderCustom.java
package com.mybatis.demo.po;public class OrderCustom extends Orders { // 用户名称 private String username; // 用户地址 private String address; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } }
resultType的使用
<select id="findOrderUserList" resulttype="com.mybatis.demo.po.OrderCustom"> SELECT orders.* , user.username , user.address FROM orders , USER WHERE orders.user_id = user.id </select></code>
使用resultMap完成例子一中的需求:
<resultmap type="orders" id="ordersUserResultMap"> <id column="id" property="id"> <result column="order_number" property="order_number"> <result column="user_id" property="user_id"> <association property="user" javatype="com.mybatis.demo.po.User"> <id column="user_id" property="id"> <result column="username" property="username"> <result column="address" property="address"> </result></result></id></association> </result></result></id></resultmap></code>
使用resultMap
<code class="language-xml hljs "><select id="findOrderUserListResultMap" resultmap="ordersUserResultMap"> SELECT orders.* , user.username , user.address FROM orders , USER WHERE orders.user_id = user.id </select></code>
例子2:订单与订单明细查询
resultMap定义如下:
<resultmap type="orders" id="ordersUserDetailResultMap" extends="ordersUserResultMap"> <collection property="orderdetails" oftype="com.mybatis.demo.po.Orderdetail"> <id column="orderdetail_id" property="id"> <result column="item_id" property="item_id"> <result column="item_num" property="item_num"> <result column="item_price" property="item_price"> </result></result></result></id></collection> </resultmap></code>
在Orders类中需要定义一个订单明细的集合对象:
//订单明细,需要给出该对象的get与set方法 private List orderdetails;
使用定义的resultMap
<select id="findOrdersUserDetailList" resultmap="ordersUserDetailResultMap"> SELECT orders.*, user.username, user.address, orderdetail.item_id, orderdetail.item_num, orderdetail.item_price FROM orders, USER, orderdetail WHERE orders.user_id = user.id AND orders.id = orderdetail.orders_id </select></code>
例子3:订单明细与商品信息
<resultmap type="orders" id="ordersUserDetailItemResultMap" extends="ordersUserResultMap"> <collection property="orderdetails" oftype="com.mybatis.demo.po.Orderdetail"> <id column="orderdetail_id" property="id"> <result column="item_id" property="item_id"> <result column="item_num" property="item_num"> <result column="item_price" property="item_price"> <association property="items" javatype="com.mybatis.demo.po.Items"> <id column="item_id" property="id"> <result column="item_name" property="item_name"> <result column="item_price" property="item_price"> <result column="item_detail" property="item_detail"> </result></result></result></id></association> </result></result></result></id></collection> </resultmap></code>
使用上述定义的resultMap
<select id="findOrderUserDetailItemList" resultmap="ordersUserDetailItemResultMap"> SELECT orders.*, user.username, user.address, orderdetail.id orderdetail_id, orderdetail.item_id, orderdetail.item_num, orderdetail.item_price , items.item_detail, items.item_name, items.item_price FROM orders, USER, orderdetail, items WHERE orders.user_id = user.id AND orders.id = orderdetail.orders_id AND orderdetail.item_id = items.id </select></code>
PO类中的定义:
在OrderDerail类中需要添加以下对象:
//商品信息 private Items items;//明细对应的商品信息
3、延迟加载
延迟加载对于上述例子中的需求:首次只查询订单信息,当需要关联查询用户信息时,再查询用户信息。 延迟加载相对于之前学习的hibernate的概念就是懒加载,先去查询主表信息,如果用到从表的数据的话,再去查询从表的信息。Mybatis中resultMap可以实现延迟加载
在sqlMapConfig.xml中进行配置与开启:
<code class="language-xml hljs "> <settings> <setting name="lazyLoadingEnabled" value="true"> <setting name="aggressiveLazyLoading" value="false"> <setting name="cacheEnabled" value="true"> </setting></setting></setting></settings></code>
在mapper中使用延迟加载:
<resultmap type="orders" id="ordersUserResultMapLazy"> <id column="id" property="id"> <result column="user_id" property="user_id"> <result column="order_number" property="order_number"> <association property="user" javatype="com.mybatis.demo.po.User" select="com.mybatis.demo.mapper.UserMapper.findUserById" column="user_id"> <id column="id" property="id"> </id></association> </result></result></id></resultmap> <select id="findOrderList" resultmap="ordersUserResultMapLazy"> select * from orders </select></code>
调试效果如下:
首先调试测试方法:
//测试延迟加载@Test public void findOrderList() throws Exception { SqlSession session = sqlSessionFactory.openSession(); OrdersMapperCustom orderMapperCustom = session.getMapper(OrdersMapperCustom.class); List list = orderMapperCustom.findOrderList(); for (Orders orders : list) { @SuppressWarnings("unused") int order_id = orders.getId(); //去订单ID;断点1 @SuppressWarnings("unused") User user = orders.getUser(); //查询用户信息;断点2 } session.close(); }
4、一级缓存
一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。 二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
首先先看一下一级缓存与二级缓存在mybatis中的关系:
一级缓存原理:
第一次查询id为X的用户,此时先去一级缓存查找,如果查找不到,则去数据库查询,把查询后的 结果存储到一级缓存中;
第二次查询id为X的用户,此时先去一级缓存查找,如果查找到,则直接从一级缓存中把数据取出,不去查询数据库;
只要中间发生增删改操作,那么一级缓存就清空;
5、二级缓存
原理
第一次查询id为1 的用户,此时先去二级缓存查找,如果查找不到,则去数据库查询,把查询后的 结果存储到二级缓存中。 第二次查询id为1 的用户,此时先去二级缓存查找,如果查找到,则直接从二级缓存中把数据取出,不去查询数据库。 只要中间发生增删改操作,那么二级缓存就清空。 二级缓存默认是不开启的。
步骤一:开启二级缓存:
在sqlMapConfig.xml中开启二级缓存总开关:
<setting name="cacheEnabled" value="true"></setting></code>
步骤二:开启二级缓存:
步骤三:对象序列化(必须)
implements Serializable
步骤四:测试即可
如何刷新缓存:
在映射文件的statement中设置flushCache=true可以刷新当前的二级缓存,默认情况下如果是select语句,那么flushCache是false。如果是insert、update、delete语句,那么flushCache是true; 如果查询语句设置成true,那么每次查询都是去数据库查询,即意味着该查询的二级缓存失效; 如果查询语句设置成false,即使用二级缓存,那么如果在数据库中修改了数据,而缓存数据还是原来的,这个时候就会出现脏读。
禁用缓存:
<code class="language-xml hljs "><select id="findUserById" parametertype="int" resulttype="user" usecache="false"> SELECT * FROM USER WHERE id = #{id} </select></code>