一级缓存在mybatis中默认是开启的并且是session级别,它的作用域为一次sqlSession会话。
1 import com.smartdata.pms.PmsApplication; 2 import com.smartdata.pms.entity.PmsProduct; 3 import com.smartdata.pms.mapper.PmsProductMapper; 4 import com.smartdata.pms.service.PmsProductService; 5 import org.junit.Test; 6 import org.junit.runner.RunWith; 7 import org.springframework.beans.factory.annotation.Autowired; 8 import org.springframework.boot.test.context.SpringBootTest; 9 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 10 import org.springframework.transaction.annotation.Transactional; 11 12 import java.util.concurrent.LinkedBlockingQueue; 13 import java.util.concurrent.ThreadPoolExecutor; 14 import java.util.concurrent.TimeUnit; 15 16 /** 17 * @ProjectName: smartdata 18 * @Package: PACKAGE_NAME 19 * @ClassName: CacheTest 20 * @Author: heluwei 21 * @Description: 缓存测试 22 * @Date: 2020/3/21 18:34 23 * @Version: 1.0 24 */ 25 @RunWith(SpringJUnit4ClassRunner.class) 26 @SpringBootTest(classes = PmsApplication.class) 27 public class CacheTest{ 28 @Autowired 29 PmsProductMapper pmsProductMapper; 30 @Test 31 @Transactional(rollbackFor = Throwable.class) 32 public void testFistCache(){ 33 // 第一次查询,缓存到一级缓存 34 System.out.println(pmsProductMapper.selectById(1)); 35 // 第二次查询,直接读取一级缓存 36 System.out.println(pmsProductMapper.selectById(1)); 37 38 } 39 }
为什么开启事务
由于使用了数据库连接池,默认每次查询完之后自动commite,这就导致两次查询使用的不是同一个sqlSessioin,根据一级缓存的原理,它将永远不会生效。
当我们开启了事务,两次查询都在同一个sqlSession中,从而让第二次查询命中了一级缓存。读者可以自行关闭事务验证此结论。
默认情况下,mybatis打开了二级缓存,但它并未生效,因为二级缓存的作用域是namespace,所以还需要在Mapper.xml文件中配置一下才能使二级缓存生效
使用Redis实现Mybatis的二级缓存。因为Mybatis的二级缓存存放在本地内存中。
一:在yml文件中
1 #配置mapper 2 mybatis: 3 #开启Mybatis的二级缓存 4 configuration: 5 cache-enabled: true
二:自定义MybatisRedisCache
package com.smartdata.pms.cache; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.cache.Cache; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.util.CollectionUtils; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @ProjectName: smartdata * @Package: com.smartdata.pms.cache * @ClassName: MyDefineRedisCache * @Author: heluwei * @Description: 使用Redis缓存Mybatis的二级缓存 * @Date: 2020/3/22 22:56 * @Version: 1.0 */ @Slf4j public class MybatisRedisCache implements Cache { // 读写锁 private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true); private static RedisTemplate redisTemplate; // private RedisTemplate<String, Object> redisTemplate = SpringContextHolder.getBean("redisTemplate"); private String id; public MybatisRedisCache(final String id) { if (id == null) { throw new IllegalArgumentException("Cache instances require an ID"); } log.info("Redis Cache id " + id); this.id = id; } @Override public String getId() { return this.id; } @Override public void putObject(Object key, Object value) { if (value != null) { // 向Redis中添加数据,有效时间是2天 redisTemplate.opsForValue().set(key.toString(), value, 2, TimeUnit.DAYS); } } @Override public Object getObject(Object key) { try { if (key != null) { Object obj = redisTemplate.opsForValue().get(key.toString()); return obj; } } catch (Exception e) { log.error(e.getMessage()); } return null; } @Override public Object removeObject(Object key) { try { if (key != null) { redisTemplate.delete(key.toString()); } } catch (Exception e) { log.error(e.getMessage()); } return null; } @Override public void clear() { log.info("清空缓存"); try { Set<String> keys = redisTemplate.keys("*:" + this.id + "*"); if (!CollectionUtils.isEmpty(keys)) { redisTemplate.delete(keys); } } catch (Exception e) { log.error(e.getMessage()); } } @Override public int getSize() { Long size = (Long) redisTemplate.execute(new RedisCallback<Long>() { @Override public Long doInRedis(RedisConnection connection) throws DataAccessException { return connection.dbSize(); } }); return size.intValue(); } @Override public ReadWriteLock getReadWriteLock() { return this.readWriteLock; } public static void setRedisConnectionFactory(RedisTemplate redisTemplate) { MybatisRedisCache.redisTemplate = redisTemplate; } }
在spring启动的时候,将redisTemplate注入到MybatisRedisCache类中
1 package com.smartdata.pms.cache; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.data.redis.core.RedisTemplate; 5 import org.springframework.stereotype.Component; 6 7 /** 8 * @ProjectName: smartdata 9 * @Package: com.smartdata.pms.cache 10 * @ClassName: RedisCacheTransfer 11 * @Author: heluwei 12 * @Description: 13 * @Date: 2020/3/22 23:19 14 * @Version: 1.0 15 */ 16 @Component 17 public class RedisCacheTransfer { 18 19 @Autowired 20 public void setJedisConnectionFactory(RedisTemplate redisTemplate) { 21 MybatisRedisCache.setRedisConnectionFactory(redisTemplate); 22 } 23 }
在xml文件中加入<cache></cache>标签
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 3 <mapper namespace="com.smartdata.pms.mapper.PmsProductMapper"> 4 <cache type="com.smartdata.pms.cache.MybatisRedisCache"> 5 <property name="eviction" value="LRU" /> 6 <property name="flushInterval" value="6000000" /> 7 <property name="size" value="1024" /> 8 <property name="readOnly" value="false" /> 9 </cache> 10 <select id="getPmsProductPage" resultType="com.smartdata.pms.entity.PmsProduct"> 11 select * from pms_product pp 12 where 1=1 13 and pp.del_flag = ‘0‘ 14 <if test="pmsProduct.proNo != null and pmsProduct.proNo != ‘‘"> 15 and pp.pro_no = #{pmsProduct.proNo} 16 </if> 17 </select> 18 19 <select id="getOneById" parameterType="Long" resultType="String"> 20 select pro_no proNo from pms_product where 1=1 and pro_id = #{pId} 21 </select> 22 </mapper>
缓存的只有在xml中的。利用Mybatis-plus,查询的接口没有效果。
测试:
1 import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 2 import com.smartdata.pms.PmsApplication; 3 import com.smartdata.pms.mapper.PmsProductMapper; 4 import org.junit.Test; 5 import org.junit.runner.RunWith; 6 import org.springframework.beans.factory.annotation.Autowired; 7 import org.springframework.boot.test.context.SpringBootTest; 8 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 9 import org.springframework.transaction.annotation.Transactional; 10 11 12 /** 13 * @ProjectName: smartdata 14 * @Package: PACKAGE_NAME 15 * @ClassName: CacheTest 16 * @Author: heluwei 17 * @Description: 缓存测试 18 * @Date: 2020/3/21 18:34 19 * @Version: 1.0 20 */ 21 @RunWith(SpringJUnit4ClassRunner.class) 22 @SpringBootTest(classes = PmsApplication.class) 23 public class CacheTest{ 24 @Autowired 25 PmsProductMapper pmsProductMapper; 26 /** 27 * @Description: 一级缓存,因为使用了连接池,每次查询自动commit。 28 */ 29 @Test 30 @Transactional(rollbackFor = Throwable.class) 31 public void testFistCache(){ 32 // 第一次查询,缓存到一级缓存 33 System.out.println(pmsProductMapper.selectById(1)); 34 // 第二次查询,直接读取一级缓存 35 System.out.println(pmsProductMapper.selectById(1)); 36 } 37 38 /** 39 * 测试二级缓存效果 40 * 需要*Mapper.xml开启二级缓存 41 **/ 42 @Test 43 public void testSecondCache(){ 44 System.out.println(pmsProductMapper.getOneById(1L)); 45 System.out.println(pmsProductMapper.getOneById(1L)); 46 System.out.println(pmsProductMapper.getOneById(1L)); 47 System.out.println(pmsProductMapper.getOneById(1L)); 48 System.out.println(pmsProductMapper.selectById(1L)); 49 System.out.println(pmsProductMapper.selectById(1L)); 50 System.out.println(pmsProductMapper.selectById(1L)); 51 System.out.println(pmsProductMapper.selectById(1L)); 52 } 53 }
原文:https://www.cnblogs.com/bulrush/p/12549568.html