使用redis作为mybatis的二级缓存
需要的jar包 需要特别说明的是 我一套jar包也是经历过实际检验的 网上很多的教程里面的包组合根本是是用不了的 无非就是版本不搭配
除了Spring必须的jar包以外 (Spring是4X)
需要jar包的可以去这个网址:http://mvnrepository.com/
这几个jar包的组合是可以用的 看网上教程提供的jar包组合太恐怖了。各种搭配失败 而且劝大家选择jar包的时候 不要一味追求高版本 要选最稳定得
好 真正开始配置缓存
首先你需要有一个redis数据库。建议是linux下的redis 要是非要使用Windows的也可以 github上有大神已经做出来了 具体的安装教程网上太多了 很幸运 都是可以用的。。
然后 你需要构建一个redis的类为了序列化需要缓存的东西到redis数据库中
package main.java.com.hdd.core.util; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.ibatis.cache.Cache; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.redis.connection.jedis.JedisConnection; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer; import redis.clients.jedis.exceptions.JedisConnectionException; public class RedisCache implements Cache //实现类 { private static final Logger logger = LoggerFactory.getLogger(RedisCache.class); private static JedisConnectionFactory jedisConnectionFactory; private final String id; /** * The {@code ReadWriteLock}. */ private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); public RedisCache(final String id) { if (id == null) { throw new IllegalArgumentException("Cache instances require an ID"); } logger.debug("MybatisRedisCache:id=" + id); this.id = id; } @Override public void clear() { JedisConnection 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; JedisConnection connection = null; try { connection = jedisConnectionFactory.getConnection(); RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer(); //借用spring_data_redis.jar中的JdkSerializationRedisSerializer.class 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; JedisConnection 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) { JedisConnection connection = null; try { logger.info(">>>>>>>>>>>>>>>>>>>>>>>>putObject:"+key+"="+value); connection = jedisConnectionFactory.getConnection(); RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer(); //借用spring_data_redis.jar中的JdkSerializationRedisSerializer.class connection.set(serializer.serialize(key), serializer.serialize(value)); //利用其序列化方法将数据写入redis服务的缓存中 } catch (JedisConnectionException e) { e.printStackTrace(); } finally { if (connection != null) { connection.close(); } } } @Override public Object removeObject(Object key) { JedisConnection 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) { RedisCache.jedisConnectionFactory = jedisConnectionFactory; } }特意贴出了导入的包 希望看清楚 别import错了
然后再来一个
package main.java.com.hdd.core.util; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; public class RedisCacheTransfer { @Autowired public void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) { RedisCache.setJedisConnectionFactory(jedisConnectionFactory); } }
再然后 Spring里面的配置 :
<context:property-placeholder location="classpath:main/resources/redis.properties" /> <!-- redis数据源 --> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxIdle" value="${redis.maxIdle}" /> <property name="maxTotal" value="${redis.maxActive}" /> <property name="maxWaitMillis" value="${redis.maxWait}" /> <property name="testOnBorrow" value="${redis.testOnBorrow}"/> </bean> <!-- Spring-redis连接池管理工厂 --> <context:property-placeholder location="classpath:main/resources/redis.properties" /> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}" p:pool-config-ref="poolConfig"/> <!-- 使用中间类解决RedisCache.jedisConnectionFactory的静态注入,从而使MyBatis实现第三方缓存 --> <bean id="redisCacheTransfer" class="main.java.com.hdd.core.util.RedisCacheTransfer"> <property name="jedisConnectionFactory" ref="jedisConnectionFactory"/> </bean>这个redis的连接池的配置 只在jedis2.4以下的版本有 具体多往下我也没研究过 如果是高版本 那么数据源那里就会有错
然后提一句 如果你已经配了jdbc的配置文件 那么需要在Spring里面这样:
<bean id="configProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="locations"> <list> <value>classpath:main/resources/jdbc.properties</value> <value>classpath:main/resources/redis.properties</value> </list> </property> <property name="fileEncoding" value="UTF-8"/> </bean> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer"> <property name="properties" ref="configProperties"/> </bean>做一个list的配置
然后redis的配置:
redis.host=127.0.0.1 redis.port=6379 redis.pass= redis.maxIdle=300 redis.maxActive=600 redis.maxWait=1000 redis.testOnBorrow=true然后都配好了之后 需要在Mybatis的配置中开启缓存 很重要
<!-- 全局映射器启用缓存 --> <setting name="cacheEnabled" value="true" />然后 准备工作算是完成了
接下来去mapper中开启redis
<cache type="main.java.com.hdd.core.util.RedisCache"/>这个是需要你每个要使用缓存的mapper中都要开启的
然后再具体在sql语句上:
<select id="getXs" resultType="main.java.com.hdd.tree.entity.Xs" useCache="true">useCache 开启 如果不使用就 改为false
很容易被忘记的一点是 现在 我们还需要去实体里面开启序列化 就是你绑定的实体到mybatis的那个实体里
public class Xk implements Serializable这样才是真正的成功了
然后我们实验一下 :
这个就是缓存命中了 第一次运行是不会命中的 我这个已经是很多次了 运行的时间大概是1.3秒 如果关闭了缓存就是7.3秒左右 提升还是很大的
然后我们看一下redis里面发生了什么变化
获取key后会出现很多奇怪的东西 但是细细看 会发现里面有sql语句 这就已经将sql执行的东西放进了redis里面 只要你不设置key的过期时间 这些key就会一直在
ok 大功告成
最终说明: 如果在mapper.xml中使用了cache标签 会默认开启这个mapper.xml下面所有的select标签使用的sql的缓存 如果不需要的话 需要手动调整为usecache=false 所以其实usecache=true是默认开启的 写不写都可以 但是不用的时候一定要给不用的方法 加上usecache=false
而且 这样的缓存数据是不会自动检测你的数据是否发生了变化 也就是说 如果你更新了数据库的数据 那么再查的时候 一定还是用的缓存 现在的解决办法没有特别好的指定更新 只能flush redis 就是在你update delete insert这种操作的mapper里面(当然是开启了缓存的查询) 加上flushCache = true 这样每次更新了数据库的时候 redis就会刷新 以前的key就没有了 这样能够保证redis的数据同步 但是同步是有时间的 不知道在高并发的时候会不会有时间差 所以最好深入研究redis 看看各种过期策略。