对于查询比较多的项目可以考虑配置二级缓存,mybatis本身的二级缓存是缓存到本地,但是对于多个节点的项目来说,可能会出现数据不一致的问题,所以采用redis缓存,这样二级缓存的数据就可以缓存到内存,可实现多个节点项目的数据同步。
1、配置redis的连接
#redis gmall.redis.host=172.16.1.250 gmall.redis.port=6379 gmall.redis.pass=Gworld2017 gmall.redis.photo.database=6 #最大分配的对象数 gmall.redis.maxActive=12000 #最大能够保持idel状态的对象数 gmall.redis.maxIdle=600 #当池内没有返回对象时,最大等待时间 gmall.redis.maxWait=2000 gmall.redis.timeout=5000 #当调用borrow Object方法时,是否进行有效性检查 gmall.redis.testOnBorrow=true #当调用return Object方法时,是否进行有效性检查 gmall.redis.testOnReturn=true gmall.redis.minIdle=5
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd" default-lazy-init="false"> <bean id="jedisConnFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" primary="true"> <property name="hostName" value="${gmall.redis.host}" /> <property name="port" value="${gmall.redis.port}" /> <property name="password" value="${gmall.redis.pass}" /> <property name="timeout" value="${gmall.redis.timeout}" /> <property name="database" value="${gmall.redis.photo.database}" /> </bean> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" primary="true"> <property name="connectionFactory" ref="jedisConnFactory" /> <property name="exposeConnection" value="true" /> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> <property name="valueSerializer"> <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" /> </property> <property name="hashKeySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> <property name="hashValueSerializer"> <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" /> </property> </bean> </beans>
2、配置mybatis-cache-config.xml文件
<?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>
3、编写RedisCache实现Cache类
package com.gcard.gwmedia.cache; 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.core.RedisTemplate; import com.gcard.gwmedia.utils.SpringBeanFactoryUtils; public class RedisCache implements Cache { Logger logger = LoggerFactory.getLogger(getClass()); private final String FREFIX = "CACHE_"; private final String id; private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true); @SuppressWarnings("rawtypes") private RedisTemplate redisTemplate; private long cleanInterval; private long lastClear; public RedisCache(String id){ if(id == null){ throw new IllegalArgumentException("Cache instance require an ID"); } this.id = id; this.cleanInterval = 1 * 60 * 60 * 1000;//一个小时 this.lastClear = System.currentTimeMillis(); } @SuppressWarnings({ "unchecked" }) @Override public void clear() { lastClear = System.currentTimeMillis(); String strKey = FREFIX + id.toString(); getRedisTemplate().delete(strKey); logger.debug("Clear all the cached query result from redis"); } @Override public String getId() { return id; } @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public Object getObject(Object key) { if(key != null){ String strKey = FREFIX + id.toString(); if(clearWhenStale(strKey)){ return null; } RedisTemplate redisTemplate = getRedisTemplate(); Object obj = redisTemplate.opsForHash().get(strKey, key.toString()); logger.debug("Get cached query result from redis"); if(obj != null){ return obj; }else{ return null; } }else{ return null; } } @SuppressWarnings("rawtypes") private RedisTemplate getRedisTemplate() { if(redisTemplate == null){ redisTemplate = (RedisTemplate) SpringBeanFactoryUtils.getBean("redisTemplate"); } return redisTemplate; } @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public void putObject(Object key, Object value) { if (key != null) { String strKey = FREFIX + id.toString(); clearWhenStale(strKey); RedisTemplate redisTemplate = getRedisTemplate(); redisTemplate.opsForHash().put(strKey,key.toString(),value); logger.debug("Put query result to redis"); } } @Override public ReadWriteLock getReadWriteLock() { return readWriteLock; } @Override public int getSize() { return 0; } @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public Object removeObject(Object key) { if (key != null) { String strKey = FREFIX + id.toString(); RedisTemplate redisTemplate = getRedisTemplate(); redisTemplate.opsForHash().delete(strKey, key.toString()); logger.debug("Remove cached query result from redis"); } return null; } public boolean clearWhenStale(Object key){ if(System.currentTimeMillis()-lastClear > cleanInterval){ logger.info("clearWhenStale key={}", key); clear(); return true; } return false; } }
4、配置mapper.xml文件
在mapper.xml文件加入<cache/>
<cache type="com.gcard.gwmedia.cache.RedisCache"/>
5、Application启动类添加注解@EnableCaching
package com.gcard.gwmedia; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.ImportResource; import org.springframework.scheduling.annotation.EnableAsync; @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) @ImportResource(locations = {"classpath:/config/applicationContext.xml"}) @EnableAsync @EnableCaching public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }