01_MyBatis的延迟加载
何为延迟加载
通过前面的学习,我们已经掌握了 Mybatis中多表查询的配置及实现,可以实现对象的关联查询。实际开发过程中很多时候我们并不需要在加载用户信息时就一定要加载他的订单信息。此时就是我们所说的延迟加载。
作用
就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.
好处
先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
应用
通常情况下,一对一查询不需要做延迟加载,一对多需要做延迟加载
02_一对一延迟加载实现
使用前提
需要在sqlMapConfig.xml配置文件中开启延迟加载
<settings><setting name="lazyLoadingEnabled" value="true"/></settings>
需求:
通过订单延迟加载相应的用户信息
POJO类
public class Customer {private Long cid;private String cname;private int cage;//get/set方法}public class Order {private Long oid;private String oname;private Customer customer;private Integer cno;//get/set方法}
映射文件
<!‐‐订单映射文件select属性:查询用户信息延迟加载的实现column属性:查询用户信息需要传递的参数,该参数从先加载的订单信息中获取.‐‐><mapper namespace="com.qzw.dao.IOrderDao"><resultMap type="com.qzw.bean.Order" id="orderCustomerMap"><id property="oid" column="oid"/><result property="oname" column="oname"/><associationproperty="customer" javaType="com.qzw.bean.Customer" select="com.qzw.dao.ICustomerDao.selectCustomerById" column="cno"></association></resultMap><select id="selectOrderList" resultMap="orderCustomerMap"> select * from tb_order;</select></mapper><!‐‐ 用户映射文件 ‐‐><select id="selectCustomerById" parameterType="int" resultType="com.qzw.bean.Customer">select * from tb_customer where cid = #{id};</select>
测试
@Testpublic void selectOrderList() {List < Order > list = orderDao.selectOrderList();//会触发查询用户信息list.get(0).getCustomer();}
03_一对多延迟加载实现
需求:
通过用户信息延迟加载相应的订单信息
POJO类
public class Customer {private Long cid;private String cname;private int cage;private List < Order > list;//get/set方法}
public class Order {private Long oid;private String oname;private Customer customer;private Integer cno;//get/set方法}
映射文件
<!‐‐用户映射文件select属性:查询订单信息延迟加载实现 column属性:查询订单信息需要传递的参数,得先从已经加载的用户信息中获取‐‐><resultMap type="com.qzw.bean.Customer" id="customerOrderMap"><id property="cid" column="cid" /><result property="cname" column="cname" /><result property="cage" column="cage" /><collectionproperty="list" ofType="com.qzw.bean.Order"select="com.qzw.dao.IOrderDao.selectOrderListByCustomerId" column="cid"></collection></resultMap><select id="selectCustomerById" parameterType="long" resultMap="customerOrderMap">select * from tb_customer where cid = #{id};</select><!‐‐订单映射文件‐‐><select id="selectOrderListByCustomerId" parameterType="long" resultMap="orderCustomerMap">select * from tb_order where cno = #{cno};</select>
测试
Customer customer = customerDao.selectCustomerById(1L);System.out.println(customer.getCname());System.out.println(customer.getList());
04_MyBatis的缓存
什么是缓存?
存储在内存中的临时数据
为什么使用缓存?
减少和数据库的交互次数,提高执行效率
应用场景
适用于缓存
经常查询并且不经常改变的
数据的正确与否对最终结果影响不大
不适用于缓存 数据经常改变的
数据的正确与否对最终结果影响不大
比如:
商品库存,银行汇率…
05_一级缓存的验证
概念
一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除, commit(),
close()等方法时,就会清空一级缓存。
验证
public interface IUserDao {public User selectUserById(Long id);}< mapper namespace = "com.qzw.dao.IUserDao" >< select id = "selectUserById"parameterType = "long"resultType = "com.qzw.bean.User" > select * from user where id = # {id}; < /select></mapper >@Testpublic void selectUserById() throws IOException {InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);SqlSession session = sessionFactory.openSession();IUserDao userDao = session.getMapper(IUserDao.class);User user1 = userDao.selectUserById(2l);session.clearCache();User user2 = userDao.selectUserById(2l);System.out.println(user1 == user2);}
05_增删改清空一级缓存
概念
如果 sqlSession去执行commit操作(执行插入、更新、删除),清空 SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息
以修改操作为例:
InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);SqlSession session = sessionFactory.openSession();IUserDao userDao = session.getMapper(IUserDao.class);User user1 = userDao.selectUserById(2l);userDao.updateUser(new User(3l, "aaaa", "aa"));User user2 = userDao.selectUserById(2l);System.out.println(user1 == user2);session.commit();session.close();
06_MyBatis的二级缓存
概念
二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql语句,多个SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。
使用步骤
开启二级缓存
<settings><!‐‐ 开启缓存的支持 ‐‐><setting name="cacheEnabled" value="true"/></settings>
在mapper映射文件配置
<mapper namespace="com.qzw.dao.IUserDao"><!‐‐ 开启二级缓存的支持 ‐‐><cache></cache></mapper>
配置statement上面的useCache属性
<!‐‐设置 useCache=”true”代表当前这个 statement 要使用二级缓存,如果不使用二级缓存可以设置为 false。‐‐><select id="findById" resultType="user" parameterType="int" useCache="true">select * from user where id = #{uid}</select>
注意事项
二级缓存存储的并不是java对象,存储的是对象所对应的字符串信息,当从二级缓存取出 时,根据对应字符串生成新的对象,所以,使用二级缓存,会发现取出对象是不同的对象。但是,sql语句只执行了一次。
测试代码
@Testpublic void selectUserById() throws IOException {InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);SqlSession session = sessionFactory.openSession();IUserDao userDao = session.getMapper(IUserDao.class);User user1 = userDao.selectUserById(2l);//销毁第一次查询的一级缓存session.close();session = sessionFactory.openSession();userDao = session.getMapper(IUserDao.class);User user2 = userDao.selectUserById(2l);//销毁第二次查询的一级缓存session.close(); System.out.println(user1 == user2);}
