概述
Mybatis默认缓存是PerpetualCache,它实现了Cache接口。Mybatis为了方便我们扩展缓存定义了一个Cache接口,因此,我们只需要参考源码自己使用redis实现Cache接口,即可达到Mybatis整合redis管理缓存的目的。
开始
本文介绍在spring-mvc的项目中,如何实现使用redis作为Mybatis的二级缓存。重点是实现Cache接口,而如何引入redis有多种方式,本文使用其中一种。
环境
- jdk:1.7
- redis:2.8.12
- spring:4.1.1.RELEASE
新建redis.properties文件
用于记录redis的基本信息
# ====================================================
# redis settings
# ====================================================
redis.host=127.0.0.1
redis.port=6379
redis.pass=
redis.maxIdle=300
redis.maxActive=600
redis.maxWait=1000
redis.testOnBorrow=false
新建RedisConfig.java类
用于获取redis配置信息
public class RedisConfig {
private static String host;
private static String port;
private static String pass;
private static String maxIdle;
private static String maxActive;
private static String maxWait;
private static String testOnBorrow;
public RedisConfig(String host, String port, String pass, String maxIdle,
String maxActive, String maxWait, String testOnBorrow) {
super();
RedisConfig.host = host;
RedisConfig.port = port;
RedisConfig.pass = pass;
RedisConfig.maxIdle = maxIdle;
RedisConfig.maxActive = maxActive;
RedisConfig.maxWait = maxWait;
RedisConfig.testOnBorrow = testOnBorrow;
}
public static String getHost() {
return host;
}
public static String getPort() {
return port;
}
public static String getPass() {
return pass;
}
public static String getMaxIdle() {
return maxIdle;
}
public static String getMaxActive() {
return maxActive;
}
public static String getMaxWait() {
return maxWait;
}
public static String getTestOnBorrow() {
return testOnBorrow;
}
public void setHost(String host) {
RedisConfig.host = host;
}
public void setPort(String port) {
RedisConfig.port = port;
}
public void setPass(String pass) {
RedisConfig.pass = pass;
}
public void setMaxIdle(String maxIdle) {
RedisConfig.maxIdle = maxIdle;
}
public void setMaxActive(String maxActive) {
RedisConfig.maxActive = maxActive;
}
public void setMaxWait(String maxWait) {
RedisConfig.maxWait = maxWait;
}
public void setTestOnBorrow(String testOnBorrow) {
RedisConfig.testOnBorrow = testOnBorrow;
}
}
spring配置文件中构造RedisConfig
<context:property-placeholder
location="classpath:redis.properties"
ignore-unresolvable="true" ignore-resource-not-found="true" />
<bean id="redisConfig" class="cn.essa.component.privilege.util.RedisConfig">
<constructor-arg index="0">
<value>${redis.host}</value>
</constructor-arg>
<constructor-arg index="1">
<value>${redis.port}</value>
</constructor-arg>
<constructor-arg index="2">
<value>${redis.pass}</value>
</constructor-arg>
<constructor-arg index="3">
<value>${redis.maxIdle}</value>
</constructor-arg>
<constructor-arg index="4">
<value>${redis.maxActive}</value>
</constructor-arg>
<constructor-arg index="5">
<value>${redis.maxWait}</value>
</constructor-arg>
<constructor-arg index="6">
<value>${redis.testOnBorrow}</value>
</constructor-arg>
</bean>
如此即可在普通类中使用RedisConfig,得到redis配置信息
新建RedisCache.java类
该类实现了org.apache.ibatis.cache.Cache接口
/**
* @ClassName: RedisCache
* @Description: 使用第三方缓存服务器redis,处理二级缓存
* @author cipher
*
*/
public class RedisCache implements Cache {
private static final Log LOG = LogFactory.getLog(RedisCache.class);
/** The ReadWriteLock. */
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private String id;
public RedisCache(final String id) {
if (id == null) {
throw new IllegalArgumentException("必须传入ID");
}
LOG.debug(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>MybatisRedisCache:id=" + id);
this.id = id;
}
@Override
public String getId() {
return this.id;
}
@Override
public int getSize() {
Jedis jedis = null;
JedisPool jedisPool = null;
int result = 0;
boolean borrowOrOprSuccess = true;
try {
jedis = CachePool.getInstance().getJedis();
jedisPool = CachePool.getInstance().getJedisPool();
result = Integer.valueOf(jedis.dbSize().toString());
} catch (JedisConnectionException e) {
LOG.error(e);
borrowOrOprSuccess = false;
if (jedis != null) {
jedisPool.returnBrokenResource(jedis);
}
} finally {
if (borrowOrOprSuccess) {
jedisPool.returnResource(jedis);
}
}
return result;
}
@Override
public void putObject(Object key, Object value) {
if (LOG.isDebugEnabled()) {
LOG.debug(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>putObject:"
+ key.hashCode() + "=" + value);
}
if (LOG.isInfoEnabled()) {
LOG.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>put to redis sql :"
+ key.toString());
}
Jedis jedis = null;
JedisPool jedisPool = null;
boolean borrowOrOprSuccess = true;
try {
jedis = CachePool.getInstance().getJedis();
jedisPool = CachePool.getInstance().getJedisPool();
jedis.set(SerializeUtil.serialize(key.hashCode()),
SerializeUtil.serialize(value));
} catch (JedisConnectionException e) {
LOG.error(e);
borrowOrOprSuccess = false;
if (jedis != null) {
jedisPool.returnBrokenResource(jedis);
}
} finally {
if (borrowOrOprSuccess) {
jedisPool.returnResource(jedis);
}
}
}
@Override
public Object getObject(Object key) {
Jedis jedis = null;
JedisPool jedisPool = null;
Object value = null;
boolean borrowOrOprSuccess = true;
try {
jedis = CachePool.getInstance().getJedis();
jedisPool = CachePool.getInstance().getJedisPool();
value = SerializeUtil.unserialize(jedis.get(SerializeUtil
.serialize(key.hashCode())));
} catch (JedisConnectionException e) {
LOG.error(e);
borrowOrOprSuccess = false;
if (jedis != null) {
jedisPool.returnBrokenResource(jedis);
}
} finally {
if (borrowOrOprSuccess) {
jedisPool.returnResource(jedis);
}
}
if (LOG.isDebugEnabled()) {
LOG.debug(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>getObject:"
+ key.hashCode() + "=" + value);
}
return value;
}
@Override
public Object removeObject(Object key) {
Jedis jedis = null;
JedisPool jedisPool = null;
Object value = null;
boolean borrowOrOprSuccess = true;
try {
jedis = CachePool.getInstance().getJedis();
jedisPool = CachePool.getInstance().getJedisPool();
value = jedis.expire(SerializeUtil.serialize(key.hashCode()), 0);
} catch (JedisConnectionException e) {
LOG.error(e);
borrowOrOprSuccess = false;
if (jedis != null) {
jedisPool.returnBrokenResource(jedis);
}
} finally {
if (borrowOrOprSuccess) {
jedisPool.returnResource(jedis);
}
}
if (LOG.isDebugEnabled()) {
LOG.debug(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>removeObject:"
+ key.hashCode() + "=" + value);
}
return value;
}
@Override
public void clear() {
Jedis jedis = null;
JedisPool jedisPool = null;
boolean borrowOrOprSuccess = true;
try {
jedis = CachePool.getInstance().getJedis();
jedisPool = CachePool.getInstance().getJedisPool();
jedis.flushDB();
jedis.flushAll();
} catch (JedisConnectionException e) {
LOG.error(e);
borrowOrOprSuccess = false;
if (jedis != null) {
jedisPool.returnBrokenResource(jedis);
}
} finally {
if (borrowOrOprSuccess) {
jedisPool.returnResource(jedis);
}
}
}
@Override
public ReadWriteLock getReadWriteLock() {
return readWriteLock;
}
/**
*
* @ClassName: CachePool
* @Description: 单例Cache池
*
*/
public static class CachePool {
JedisPool pool;
private static final CachePool CACHEPOOL = new CachePool();
public static CachePool getInstance() {
return CACHEPOOL;
}
private CachePool() {
try {
int maxIdle = Integer
.valueOf(RedisConfig.getMaxIdle());
long maxWait = Long.valueOf(RedisConfig.getMaxWait());
int maxActive = Integer.valueOf(RedisConfig.getMaxActive());
String redisHost = RedisConfig.getHost();
int redisPort = Integer.valueOf(RedisConfig.getPort());
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxIdle(maxIdle);
config.setMaxWait(maxWait);
config.setMaxActive(maxActive);
config.setTestOnBorrow(false);
pool = new JedisPool(config, redisHost, redisPort);
} catch (Exception e) {
LOG.error(e);
throw new RuntimeException("初始化连接池错误");
}
}
public Jedis getJedis() {
Jedis jedis = null;
boolean borrowOrOprSuccess = true;
try {
jedis = pool.getResource();
} catch (JedisConnectionException e) {
LOG.error(e);
borrowOrOprSuccess = false;
if (jedis != null) {
pool.returnBrokenResource(jedis);
}
} finally {
if (borrowOrOprSuccess) {
pool.returnResource(jedis);
}
}
jedis = pool.getResource();
return jedis;
}
public JedisPool getJedisPool() {
return this.pool;
}
}
private static class SerializeUtil {
public static byte[] serialize(Object object) {
ObjectOutputStream oos = null;
ByteArrayOutputStream baos = null;
byte[] bytes = null;
try {
// 序列化
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(object);
bytes = baos.toByteArray();
return bytes;
} catch (Exception e) {
LOG.error(e);
}
return bytes;
}
public static Object unserialize(byte[] bytes) {
if (bytes == null) {
return null;
}
ByteArrayInputStream bais = null;
try {
// 反序列化
bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
} catch (Exception e) {
LOG.error(e);
}
return null;
}
}
}
新建LoggingRedisCache.java类
该类继承了org.apache.ibatis.cache.decorators.LoggingCache,是缓存的入口类
public class LoggingRedisCache extends LoggingCache {
public LoggingRedisCache(String id) {
super(new RedisCache(id));
}
}
使用缓存
在需要使用缓存的mapper文件中加入(要在<mapper>标签范围内):
<cache type="cn.essa.component.privilege.cache.LoggingRedisCache" />
注意:测试时请记得开启redis