Mybatis-笔记2缓存验证

缓存
一级缓存
默认开启,将查询的记录缓存在 SqlSession 中,同一个session 下次再查询时直接命中。
好处:减轻数据库压力
问题:会有脏数据 当session1 中查询过一次数据之后,session2 更新数据并提交事务,session1再次查询数据,数据还是原来的状态。重
更新策略:本session 内进行 update delete 操作 的时候清空缓存中的内容(即使更新的不是缓存中的对象也会清空)。
新开启一个session 查询到的就是 新的数据.

如果不想从缓存中获取数据可以 先清理缓存 再查询session.clearCache()

既然有脏数据的问题,为什么还默认开启一级缓存?因为很少会再一个session 中多次获取同一个对象。写程序的时候应该注意。

缓存验证
查询两次数据只执行了一次sql查询

 UserMapper  mapper=  getSqlSession().getMapper(UserMapper.class);
            User user= mapper.selectByPrimaryKey("1");
            System.out.println(user.getName());
             user= mapper.selectByPrimaryKey("1");
            System.out.println(user.getName());

结果: 在这里插入图片描述
验证脏数据:

    session=getSqlSession();
    SqlSession session2=getSqlSession();
    UserMapper  mapper= session.getMapper(UserMapper.class);
    UserMapper  mapper2= session2.getMapper(UserMapper.class);
    User user= mapper.selectByPrimaryKey("1");
    System.out.println("session1第一次查询的值:"+user.getName());

    user= mapper.selectByPrimaryKey("1");
    System.out.println("session1查询到缓存的值:"+user.getName());

    user= mapper2.selectByPrimaryKey("1");
    System.out.println("session2查询到的值:"+user.getName());

session1执行完第一次查询后,用断点暂停,用另外一个sessiong更新数据并提交事务。
如下:

  session=getSqlSession();
    UserMapper  mapper= session.getMapper(UserMapper.class);
    User user= mapper.selectByPrimaryKey("1");
    System.out.println(user.getName());
    User u2= new User();u2.setId(user.getId());u2.setSex(user.getSex());
    u2.setName("username23");
    mapper.updateByPrimaryKey(u2);
    session.commit();

更新完成后 继续执行程序1中 session1 的第二次查询和 session2 中第一次查询 结果如下:
在这里插入图片描述

二级缓存
默认关闭,不建议使用,一般用redis等第三方缓存来替代。

开启方式
settings 配置 cacheEnabled


同时Mapp.xml 文件中 增加 cache 标签 开启本 Mapper 的 二级缓存

同时Map.xml 文件中 的 select 标签 可以通过 useCache 设置是否缓存查询结果 默认为true

代码:

SqlSession  session=getSqlSession();
            SqlSession session2=getSqlSession();
            UserMapper  mapper= session.getMapper(UserMapper.class);
            UserMapper  mapper2= session2.getMapper(UserMapper.class);
            User user= mapper.selectByPrimaryKey("1");
            System.out.println("session1第一次查询的值:"+user.getName());
            user= mapper.selectByPrimaryKey("1");
            System.out.println("session1查询到缓存的值:"+user.getName());
            session.close();
            user= mapper2.selectByPrimaryKey("1");
            System.out.println("session2查询到的值:"+user.getName());
            session2.close();

执行结果 可以看到 只执行了一次sql语句,第二次查询是从 session 的一级缓存中获得的所以二级缓存命中为0 ,第三次查询从二级缓存中获得, 命中率为 0.3333,(只有当查询的session 关闭后,才会缓存到二级缓存,如果session 1在session2 查询前未关闭那么,session无法从缓存中命中):

18:45:28.670 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@351d0846]
18:45:28.673 [main] DEBUG com.test.mybatis.mapper.UserMapper.selectByPrimaryKey - ==>  Preparing: select id, name, sex from user where id = ? 
18:45:28.701 [main] DEBUG com.test.mybatis.mapper.UserMapper.selectByPrimaryKey - ==> Parameters: 1(String)
18:45:28.719 [main] DEBUG com.test.mybatis.mapper.UserMapper.selectByPrimaryKey - <==      Total: 1
session1第一次查询的值:username23_fix
18:45:28.720 [main] DEBUG com.test.mybatis.mapper.UserMapper - Cache Hit Ratio [com.test.mybatis.mapper.UserMapper]: 0.0
session1查询到缓存的值:username23_fix
18:45:28.726 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@351d0846]
18:45:28.727 [main] DEBUG org.apache.ibatis.transaction.jdbc.JdbcTransaction - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@351d0846]
18:45:28.727 [main] DEBUG org.apache.ibatis.datasource.pooled.PooledDataSource - Returned connection 891095110 to pool.
18:45:28.728 [main] DEBUG com.test.mybatis.mapper.UserMapper - Cache Hit Ratio [com.test.mybatis.mapper.UserMapper]: 0.3333333333333333
session2查询到的值:username23_fix

二级缓存以Mapper 命名空间为单位,有脏数据的问题 和 缓存刷新粒度粗的问题:
脏数据问题:UserMapper 查询了 Teacher 表的数据 做了缓存。TeacherMapper 中对 teacher 表数据做了更新,然后刷新了 TeacherMapper 的缓存但是 UserMapper 表中的缓存没有清空,就有了脏数据。
**粒度粗的问题:**不管增删改 那一条数据,只要有增删改操作 那么 该Mapper 下的缓存全部清空。

分布式缓存
们系统为了提高系统并发,性能、一般对系统进行分布式部署(集群部署方式)
不使用分布缓存,缓存的数据在各各服务单独存储,会有重复缓存的情况浪费资源。所以要使用分布式缓存对缓存数据进行集中管理。mybatis无法实现分布式缓存,需要和其它分布式缓存框架进行整合。其他第三方只要实现Mybatis 的Cache 接口 ,并实现指定功能即可。这里和redis整合
事先准备好redis服务.
然后 Mybatis 工程 增加依赖:

<dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-redis</artifactId>
            <version>1.0.0-beta2</version>
        </dependency>

增加redis 配置文件 redis.properties内容如下(配置好redis 的地址端口和超时时间):

host=zk01
port=6379
connectionTimeout=5000
soTimeout=5000
password=
database=0
clientName=

UserMapper.xml 中 配置缓存实现为org.mybatis.caches.redis.RedisCache 该类实现了Mybatis 的Cache接口

<cache type="org.mybatis.caches.redis.RedisCache"  eviction="FIFO"  flushInterval="6000"  size="512"  readOnly="true" />

然后执行UserMapper 的查询操作 redis 中多了缓存内容如下,可以看到缓存的键组成为:命名空间+方法名++sql+参数值+数据源:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

catch that elf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值