每天多学一点点~
闲来无事,研究一下mybatis一二级缓存
话不多说,这就开始吧…
①、一级缓存的生命周期有多长?
a、MyBatis在开启一个数据库会话时,会 创建一个新的SqlSession对象,SqlSession对象中会有一个新的Executor对象。Executor对象中持有一个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。
b、如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用。
c、如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用。
d、SqlSession中执行了任何一个update操作(update()、delete()、insert()) ,都会清空PerpetualCache对象的数据,但是该对象可以继续使用
②、怎么判断某两次查询是完全相同的查询?
mybatis认为,对于两次查询,如果以下条件都完全一样,那么就认为它们是完全相同的两次查询。
a、传入的statementId
b、查询时要求的结果集中的结果范围
c、 这次查询所产生的最终要传递给JDBC java.sql.Preparedstatement的Sql语句字符串(boundSql.getSql() )
d、传递给java.sql.Statement要设置的参数值
简单来说:二级缓存就是xml文件的namespace级别的缓存
#mybatis 配置
mybatis.mapper-locations=classpath:/mapper/*
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.call-setters-on-nulls= true
# 开启mybatis 开启二级 缓存
mybatis.configuration.cache-enabled=true
yml配置
# redis设置
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.database=4
spring.redis.password=123456
配置类
@Configuration
public class RedisConfig {
/**
* 设置redis的序列化方式
* @param redisConnectionFactory
* @return
*/
@Bean
public RedisTemplate
配置redis二级缓存,只需要实现Cache这个接口就可以,话不多说,上代码。博主这里为了方便直接用redisTemplate;
/**
* @Auther: 爆裂无球 redis 作为 mybatis的二级缓存
* @Date: 2019/5/27 14:32
* @Description:
*/
public class MybatisRedisCache implements Cache {
private static final Logger logger = LoggerFactory.getLogger(MybatisRedisCache.class);
// 读写锁
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);
private static RedisTemplate redisTemplate;
// private RedisTemplate redisTemplate = SpringContextHolder.getBean("redisTemplate");
private String id;
public MybatisRedisCache(final String id) {
if (id == null) {
throw new IllegalArgumentException("Cache instances require an ID");
}
logger.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) {
logger.error(e.getMessage());
}
return null;
}
@Override
public Object removeObject(Object key) {
try {
if (key != null) {
redisTemplate.delete(key.toString());
}
} catch (Exception e) {
logger.error(e.getMessage());
}
return null;
}
@Override
public void clear() {
logger.info("清空缓存");
try {
Set keys = redisTemplate.keys("*:" + this.id + "*");
if (!CollectionUtils.isEmpty(keys)) {
redisTemplate.delete(keys);
}
} catch (Exception e) {
logger.error(e.getMessage());
}
}
@Override
public int getSize() {
Long size = (Long) redisTemplate.execute(new RedisCallback() {
@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类中
/**
* @Auther: 爆裂无球 将redisTemplate注入
* @Date: 2019/5/27 15:04
* @Description:
*/
@Component
public class RedisCacheTransfer {
@Autowired
public void setJedisConnectionFactory(RedisTemplate redisTemplate) {
MybatisRedisCache.setRedisConnectionFactory(redisTemplate);
}
}
/**
* @Auther: 爆裂无球 @CacheNamespace 主要用于mybatis二级缓存,但是要注意:配置文件和接口注释是不能够配合使用的。只能通过全注解的方式或者全部通过xml配置文件的方式使用
* @Date: 2019/4/26 10:11
* @Description:
*/
@CacheNamespace(implementation = MybatisRedisCache.class)
public interface Userdao {
@Insert("insert into user (id,username,sex) values (#{id},#{username},#{sex})")
int insert(User user);
@Select(" select * from user ")
List getAll();
@Select(" select id from user ")
List getAll2();
}
注:若xml中写了cache标签,则mapper中不要加@CacheNamespace注解,不然会冲突的;两者取其一
如图,第一次查询的时候打印除了sql语句,其他四次走了缓存;Cache Hit Ratio是缓存命中率;再点一次,就全部是1了。因为此时已经在redis中产生了缓存;
此时,若在 其中插入一条修改语句(增删改),则会清空一次缓存,再重新放入;目的:为了数据的一致性;
世上无难事,只怕有心人,每天积累一点点,fighting!!!