mybatis 缓存

本文介绍了MyBatis的缓存机制,缓存可提高系统性能,一般存于高速读写存储器。MyBatis有一级和二级缓存,一级缓存是SqlSession上的缓存,默认开启;二级缓存是SqlSessionFactory上的缓存,开启需在映射文件加<cache/>,且POJO要实现Serializable接口。还提到了缓存配置项。

  在MyBatis中允许使用缓存,缓存一般都放置在可高速读/写的存储器上,比如服务器的内存,它能够有效提高系统的性能。因为数据库在大部分场景下是把存储在磁盘上的数据索引出来。从硬件的角度分析,索引磁盘是一个较为缓慢的过程,读取内存或者高速缓存处理器的速度要比读取磁盘快得多,其速度是读取硬盘的几十倍到上百倍,但是内存和高速缓存处理器的空间有限,所以一般只会把那些常用且命中率高的数据缓存起来,以便将来使用,而不缓存那些不常用且命中率低的数据缓存。因为命中率低,最后还是要在磁盘内查找,并不能有效提高性能。
  MyBatis分为一级缓存和二级缓存,同时也可以配置关于缓存的设置。

一级缓存和二级缓存

  一级缓存是在SqlSession上的缓存,二级缓存是在SqlSes-sionFactory上的缓存。默认情况下,也就是没有任何配置的情况下,MyBatis系统会开启一级缓存,也就是对于SqlSession层面的缓存,这个缓存不需要POJO对象可序列化(实现java.io.Serializable接口)。
  首先在没有任何配置的环境下,测试一级缓存。虽然代码对同一对象进行了两次获取,但是实际只有一条SQL被执行,其原因是代码使用了同一个SqlSession对象获取数据。当一个SqlSession第一次通过SQL和参数获取对象后,它就会将其缓存起来,如果下次的SQL和参数都没有发生变化,并且缓存没有超时或者声明需要刷新时,那么它就会从缓存中获取数据,而不是通过SQL获取了。
  一级缓存是在SqlSession层面的,对于不同的SqlSession对象是不能共享的。为了使SqlSession对象之间共享相同的缓存,有时候需要开启二级缓存,开启二级缓存很简单,只要在映射文件(.xml)上加入代码:<cache/>这个时候MyBatis会序列化和反序列化对应的POJO,也就要求POJO是一个可序列化的对象,那么它就必须实现java.io.Serializable接口。对类对象进行缓存,那么就需要它实现Serializable接口
  如果Role类没有实现java.io.Serializable接口,那么MyBatis将会抛出异常,导致程序运行错误。
  不同的SqlSession在获取同一条记录,都只是发送过一次SQL获取数据。因为这个时候MyBatis将其保存在SqlSessionFactory层面,可以提供给各个SqlSession使用,只是它需要一个序列化和反序列化的过程而已,因此它需要实现Serializable接口。

SqlSession sqlSession = null;
        SqlSession sqlSession2 = null;
        try {
            sqlSession = SqlSessionFactoryUtils.openSqlSession();
            sqlSession2 = SqlSessionFactoryUtils.openSqlSession();

            RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
            Role role = roleMapper.getRole(1L);  //需要提交,如果是一级缓存,MyBatis才会缓存对象到SqlSessionFactory层面
            System.out.println(role.toString());
            sqlSession.commit();

            logger.info("不同sqlSession再获取一次POJO......");

            RoleMapper roleMapper2 = sqlSession2.getMapper(RoleMapper.class);
            Role role2 = roleMapper2.getRole(1L);  //需要提交,MyBatis才缓存对象到SqlSessionFactory
            System.out.println(role2.toString());
            sqlSession2.commit();

        } catch (Exception e) {
            logger.info(e.getMessage(), e);
        } finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
            if (sqlSession2 != null) {
                sqlSession.close();
            }
        }

 

缓存配置项

  为了测试一级缓存,只配置了cache元素,加入了这个元素后,MyBatis就会将对应的命名空间内所有select元素SQL查询结果进行缓存,而其中的insert、delete和update语句在操作时会刷新缓存。缓存要明确cache元素的配置项,如表所示。

 

转载于:https://www.cnblogs.com/ooo0/p/10951636.html

### 三级标题:MyBatis 缓存机制的工作原理 MyBatis 提供了两种级别的缓存机制:一级缓存和二级缓存,分别适用于不同的使用场景,并通过特定的数据结构实现查询结果的存储与复用。 一级缓存是 SqlSession 级别的缓存,默认情况下是开启的。每个 SqlSession 都会维护一个本地缓存(基于 HashMap 实现),用于存储该 SqlSession 中执行过的查询结果。在同一个 SqlSession 中,如果执行相同的查询语句,则 MyBatis 会直接从缓存中获取数据,而不会再次访问数据库[^3]。当执行插入、更新或删除操作时,MyBatis 会自动清空当前 SqlSession 的一级缓存,以确保数据的一致性[^1]。 二级缓存是 Mapper(namespace)级别的缓存,多个 SqlSession 可以共享同一个 Mapper 的二级缓存。这意味着跨 SqlSession 的查询可以复用缓存数据,前提是这些查询属于相同的 Mapper 命名空间。二级缓存需要显式配置,可以通过接口注解方式实现,例如使用 `@CacheNamespace` 注解来启用指定 Mapper 接口的二级缓存功能[^2]。 以下是一个使用注解方式配置 MyBatis 二级缓存的示例: ```java @CacheNamespace public interface UserMapper { User getUserById(int id); } ``` ### 三级标题:MyBatis 缓存的使用注意事项 尽管缓存机制可以显著提升数据库查询性能,但在实际应用中需要注意以下几点。 首先,一级缓存的作用范围仅限于当前 SqlSession,不同 SqlSession 之间的缓存数据互不影响。因此,在涉及多个 SqlSession 或事务隔离级别较高的场景下,不能依赖一级缓存保证数据一致性[^4]。 其次,二级缓存虽然支持跨 SqlSession 共享数据,但其默认实现并不具备线程安全特性。在并发访问频繁的环境中,建议引入第三方缓存组件(如 Ehcache 或 Redis)以提高稳定性和可扩展性。此外,二级缓存的生命周期独立于 SqlSession,即使关闭或清除 SqlSession,缓存数据依然存在,因此必须谨慎管理缓存更新策略,避免出现脏读问题[^1]。 最后,由于缓存机制的存在,某些情况下可能会导致查询结果与数据库中的最新数据不一致。为了解决这一问题,可以在执行写操作后手动刷新缓存,或者通过配置合理的缓存失效时间来控制数据同步的粒度。同时,应避免对频繁更新的数据使用缓存,以免因频繁清空缓存而抵消性能优化效果[^3]。 ### 三级标题:相关代码示例 以下是一个展示 MyBatis 一级缓存行为的简单示例。在这个例子中,两次调用相同的查询方法将只触发一次数据库访问: ```java public class UserService { @Autowired private SqlSession sqlSession; public void testCache() { UserMapper mapper = sqlSession.getMapper(UserMapper.class); // 第一次查询,结果从数据库中获取 User user1 = mapper.getUserById(1); // 第二次查询相同的记录,结果从一级缓存中获取,不再访问数据库 User user2 = mapper.getUserById(1); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值