springboot+mybatis+redis 二级缓存问题实例详解
|
前言 什么是mybatis二级缓存? 二级缓存是多个sqlsession共享的,其作用域是mapper的同一个namespace。 即,在不同的sqlsession中,相同的namespace下,相同的sql语句,并且sql模板中参数也相同的,会命中缓存。 第一次执行完毕会将数据库中查询的数据写到缓存,第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。 Mybatis默认没有开启二级缓存,需要在全局配置(mybatis-config.xml)中开启二级缓存。 本文讲述的是使用Redis作为缓存,与springboot、mybatis进行集成的方法。 1、pom依赖 使用springboot redis集成包,方便redis的访问。redis客户端选用Jedis。 另外读写kv缓存会进行序列化,所以引入了一个序列化包。 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-redis</artifactId> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.8.0</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.19</version> </dependency> 依赖搞定之后,下一步先调通Redis客户端。 2、Redis访问使用的Bean 增加Configuration,配置jedisConnectionFactory bean,留待后面使用。 一般来讲,也会生成了redisTemplate bean,但是在接下来的场景没有使用到。
@Configuration
public class RedisConfig {
@Value("${spring.redis.host}")
private String host;
// 篇幅受限,省略了
@Bean
public JedisPoolConfig getRedisConfig(){
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxIdle(maxIdle);
config.setMaxTotal(maxTotal);
config.setMaxWaitMillis(maxWaitMillis);
config.setMinIdle(minIdle);
return config;
}
@Bean(name = "jedisConnectionFactory")
public JedisConnectionFactory getConnectionFactory(){
JedisConnectionFactory factory = new JedisConnectionFactory();
JedisPoolConfig config = getRedisConfig();
factory.setPoolConfig(config);
factory.setHostName(host);
factory.setPort(port);
factory.setDatabase(database);
factory.setPassword(password);
factory.setTimeout(timeout);
return factory;
}
@Bean(name = "redisTemplate")
public RedisTemplate<?,?> getRedisTemplate(){
RedisTemplate<?,?> template = new StringRedisTemplate(getConnectionFactory());
return template;
}
}
这里使用@Value读入了redis相关配置,有更简单的配置读取方式(@ConfigurationProperties(prefix=...)),可以尝试使用。 Redis相关配置如下 #redis spring.redis.host=10.93.84.53 spring.redis.port=6379 spring.redis.password=bigdata123 spring.redis.database=15 spring.redis.timeout=0 spring.redis.pool.maxTotal=8 spring.redis.pool.maxWaitMillis=1000 spring.redis.pool.maxIdle=8 spring.redis.pool.minIdle=0 Redis客户端的配置含义,这里不再讲解了。pool相关的一般都和性能有关,需要根据并发量权衡句柄、内存等资源进行设置。 Redis客户端设置好了,我们开始配置Redis作为Mybatis的缓存。 3、Mybatis Cache 这一步是最为关键的一步。实现方式是实现Mybatis的一个接口org.apache.ibatis.cache.Cache。 这个接口设计了写缓存,读缓存,销毁缓存的方式,和访问控制读写锁。 我们实现实现Cache接口的类是MybatisRedisCache。 MybatisRedisCache.java
public class MybatisRedisCache implements Cache {
private static JedisConnectionFactory jedisConnectionFactory;
private final String id;
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public MybatisRedisCache(final String id) {
if (id == null) {
throw new IllegalArgumentException("Cache instances require an ID");
}
this.id = id;
}
@Override
public void clear() {
RedisConnection connection = null;
try {
connection = jedisConnectionFactory.getConnection();
connection.flushDb();
connection.flushAll();
} catch (JedisConnectionException e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.close();
}
}
}
@Override
public String getId() {
return this.id;
}
@Override
public Object getObject(Object key) {
Object result = null;
RedisConnection connection = null;
try {
connection = jedisConnectionFactory.getConnection();
RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer();
result = serializer.deserialize(connection.get(serializer.serialize(key)));
} catch (JedisConnectionException e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.close();
}
}
return result;
}
@Override
public ReadWriteLock getReadWriteLock() {
return this.readWriteLock;
}
@Override
public int getSize() {
int result = 0;
RedisConnection connection = null;
try {
connection = jedisConnectionFactory.getConnection();
result = Integer.valueOf(connection.dbSize().toString());
} catch (JedisConnectionException e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.close();
}
}
return result;
}
@Override
public void putObject(Object key,Object value) {
RedisConnection connection = null;
try {
connection = jedisConnectionFactory.getConnection();
RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer();
connection.set(serializer.serialize(key),serializer.serialize(value));
} catch (JedisConnectionException e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.close();
}
}
}
@Override
public Object removeObject(Object key) {
RedisConnection connection = null;
Object result = null;
try {
connection = jedisConnectionFactory.getConnection();
RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer();
result = connection.expire(serializer.serialize(key),0);
} catch (JedisConnectionException e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.close();
}
}
return result;
}
public static void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) {
MybatisRedisCache.jedisConnectionFactory = jedisConnectionFactory;
}
}
注意: 可以看到,这个类并不是由Spring虚拟机管理的类,但是,其中有一个静态属性jedisConnectionFactory需要注入一个Spring bean,也就是在RedisConfig中生成的bean。 在一个普通类中使用Spring虚拟机管理的Bean,一般使用Springboot自省的SpringContextAware。 这里使用了另一种方式,静态注入的方式。这个方式是通过RedisCacheTransfer来实现的。 4、静态注入 RedisCacheTransfer.java
@Component
public class RedisCacheTransfer {
@Autowired
public void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) {
MybatisRedisCache.setJedisConnectionFactory(jedisConnectionFactory);
}
}
可以看到RedisCacheTransfer是一个springboot bean,在容器创建之初进行初始化的时候,会注入jedisConnectionFactory bean给setJedisConnectionFactory方法的传参。 而setJedisConnectionFactory通过调用静态方法设置了类MybatisRedisCache的静态属性jedisConnectionFactory。 这样就把spring容器管理的jedisConnectionFactory注入到了静态域。 到这里,代码基本已经搞定,下面是一些配置。主要有(1)全局开关;(2)namespace作用域开关;(3)Model实例序列化。 5、Mybatis二级缓存的全局开关 前面提到过,默认二级缓存没有打开,需要设置为true。这是全局二级缓存的开关。 Mybatis的全局配置。 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 全局参数 --> <settings> <!-- 使全局的映射器启用或禁用缓存。 --> <setting name="cacheEnabled" value="true"/> </settings> </configuration> 全局配置的加载在dataSource中可以是这样的。 bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mybatis-mapper/*.xml")); 指定了mapper.xml的存放路径,在mybatis-mapper路径下,所有后缀是.xml的都会读入。 bean.setConfigLocation(new ClassPathResource("mybatis-config.xml")); (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
