【浅学Mybatis(三)】

前面学习了mybatis的基础内容,接下来是关于mybatis的缓存机制的内容。

文章目录

  • Mybatis缓存
  • 一、缓存的工作原理
  • 二、MyBatis缓存
    • 1.一级缓存
    • 2.二级缓存
  • 注意


Mybatis缓存

MyBatis是基于JDBC的封装,使数据库操作更加便捷;MyBatis除了对JDBC操作步骤进行封装之外也对其性能进行了优化:

  • 在MyBatis引入缓存机制,用于提升MyBatis的检索效率
  • 在MyBatis引入延迟加载机制,用于减少对数据库不必要的访问

注意:以下主要针对mybatis的缓存机制进行叙述


一、缓存的工作原理

缓存,就是存储数据的内存

  • 如果存在缓存则在查询的时候会先去缓存里查询,而不是直接去数据库查询。可以大大的提高检索效率

二、MyBatis缓存

MyBatis缓存分为一级缓存和二级缓存

1.一级缓存

一级缓存也叫做SqlSession级缓存,为每个SqlSession单独分配的缓存内存,无需手动开启可直接使用;多个SqlSession的缓存是不共享的。

特性:
1.如果多次查询使用的是同一个SqlSession对象,则第一次查询之后数据会存放到缓存,后续的查询则直接访问缓存中存储的数据;
2.如果第一次查询完成之后,对查询出的对象进行修改(此修改会影响到缓存),第二次查询会直接访问缓存,造成第二次查询的结果与数据库不一致;
3.当我们进行在查询时想要跳过缓存直接查询数据库,则可以通过sqlSession.clearCache();来清除当前SqlSession的缓存;
4.如果第一次查询之后第二查询之前,使用当前的sqlsession执行了修改操作,此修改操作会使第一次查询并缓存的数据失效,因此第二次查询会再次访问数据库。

//获取session
SqlSession session = sqlSessionFactory.openSession();
//获限mapper接口实例
UserMapper userMapper = session.getMapper(UserMapper.class);
//第一次查询
User user1 = userMapper.findUserById(1);
System.out.println(user1);
//在同一个session执行更新
User user_update = new User();
user_update.setId(1);
user_update.setUsername("李奎");
userMapper.updateUser(user_update);
session.commit();
//第二次查询,虽然是同一个session但是由于执行了更新操作session的缓存被清空,这里重新发出sql操作
User user2 = userMapper.findUserById(1);
System.out.println(user2);

2.二级缓存

二级缓存也称为SqlSessionFactory级缓存,通过同一个factory对象获取的Sqlsession可以共享二级缓存;在应用服务器中SqlSessionFactory是单例的,因此我们二级缓存可以实现全局共享。

特性:

1.二级缓存默认没有开启,需要在mybatis-config.xml中的settings标签开启

2.二级缓存只能缓存实现序列化接口的对象
3.禁用二级缓存:在 statement 中设置 useCache=false 可以禁用当前 select 语句的二级缓存,即每次查询都会发出 sql 去查询,默认情况是 true,即该 sql 使用二级缓存。

<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">

注意:在mybatis-config.xml开启使用二级缓存

<settings>
    <setting name="cacheEnabled" value="true"/>
</settings>
  • 测试
//获取session1
SqlSession session1 = sqlSessionFactory.openSession();
UserMapper userMapper = session1.getMapper(UserMapper.class);
//使用session1执行第一次查询
User user1 = userMapper.findUserById(1);
System.out.println(user1);
//关闭session1
session1.close();
//获取session2
SqlSession session2 = sqlSessionFactory.openSession();
UserMapper userMapper2 = session2.getMapper(UserMapper.class);//使用session2执行第二次查询,由于开启了二级缓存这里从缓存中获取数据不再向数据库发出sql
User user2 = userMapper2.findUserById(1);
System.out.println(user2);
//关闭session2
session2.close();

注意

在写一级缓存的时候遇到了两次查询与数据库数据不一致问题,即第一次查询到数据后对数据进行了修改,但是第二次查询的数据仍然和第一次相同。

分析:

  • 修改操作和查询查找不是一个线程,因此使用的是不同的Dao对象(不同的sqlsession),所以修改操作不会导致查询操作的缓存失效,第二次查询的仍然是第一次查询操作的缓存没有查数据库。

解决方案:

  • 让修改和查询操作使用相同的Sqlsession(实际上是不合理的)
  • 在查询之后清除缓存,在进行更新操作

注意:此文章为学习记录文章,参考多篇文章,如有不正之处请指教

你可能感兴趣的:(缓存,java,redis)