整体思路
之前已经有人做过mybatis+redis在spring环境的集成(http://blog.csdn.net/xiadi934/article/details/50786293)。 这里我们试试在spring boot中的集成,其中的一些注意点是不同的。特别是spring boot 的对mybatis的集成时候可以非常简单,但是在加入二级缓存时候,我们要考虑mybatis的配置。
pom 中加入依赖
<boot.version>1.3.1.RELEASE</boot.version>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
<version>${boot.version}</version>
</dependency>
applicationContext-cache.xml中引入redis配置
<!-- redis数据源 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${spring.redis.maxIdle}" />
<property name="maxTotal" value="${spring.redis.maxActive}" />
<property name="maxWaitMillis" value="${spring.redis.maxWait}" />
<property name="testOnBorrow" value="${spring.redis.testOnBorrow}" />
</bean>
<!-- Spring-redis连接池管理工厂 -->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="${spring.redis.host}" p:port="${spring.redis.port}" p:password="${spring.redis.password}" p:pool-config-ref="poolConfig"/>
<!-- 使用中间类解决RedisCache.jedisConnectionFactory的静态注入,从而使MyBatis实现第三方缓存 -->
<bean id="redisCacheTransfer" class="com.wedo.stream.cache.RedisCacheTransfer">
<property name="jedisConnectionFactory" ref="jedisConnectionFactory"/>
</bean>
实现Cache接口
这个和原来的完全一致。
RedisCache
public class RedisCache implements Cache {
private static 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();
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 {
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) {
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;
}
}
RedisCacheTransfer
public class RedisCacheTransfer
{
@Autowired
public void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) {
RedisCache.setJedisConnectionFactory(jedisConnectionFactory);
}
}
配置文件application.yml 中添加
#Redis settings
spring:
redis:
host: 127.0.0.1
password: aaa
port: 6379
mybatis:
mapperLocations: classpath*:com/wedo/stream/dao/xml/*.xml
typeAliasesPackage: com.wedo.stream.dao.entity
configLocation: classpath:mybatis-config.xml
Mybatis全局配置mybatis-config.xml
注意这个原本是不需要的,并且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="mapUnderscoreToCamelCase" value="true" />
<!-- 这个配置使全局的映射器启用或禁用缓存。系统默认值是true,设置只是为了展示出 来 -->
<setting name="cacheEnabled" value="true" />
<!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载。 系统默认值是true,设置只是为了展示出来 -->
<setting name="lazyLoadingEnabled" value="true" />
<!-- 允许或不允许多种结果集从一个单独的语句中返回(需要适合的驱动)。 系统默认值是true,设置只是为了展示出来 -->
<setting name="multipleResultSetsEnabled" value="true" />
<!--使用列标签代替列名。不同的驱动在这方便表现不同。参考驱动文档或充分测试两种方 法来决定所使用的驱动。 系统默认值是true,设置只是为了展示出来 -->
<setting name="useColumnLabel" value="true" />
<!--允许 JDBC 支持生成的键。需要适合的驱动。如果设置为 true 则这个设置强制生成的键被使用,尽管一些驱动拒绝兼容但仍然有效(比如
Derby)。 系统默认值是false,设置只是为了展示出来 -->
<setting name="useGeneratedKeys" value="false" />
<!--配置默认的执行器。SIMPLE 执行器没有什么特别之处。REUSE 执行器重用预处理语句。BATCH 执行器重用语句和批量更新 系统默认值是SIMPLE,设置只是为了展示出来 -->
<setting name="defaultExecutorType" value="SIMPLE" />
<!--设置超时时间,它决定驱动等待一个数据库响应的时间。 系统默认值是null,设置只是为了展示出来 -->
<setting name="defaultStatementTimeout" value="25000" />
</settings>
</configuration>
mapper中加入MyBatis二级缓存
<mapper namespace="com.wedo.stream.dao.mapper.SorterMapper" >
<cache type="com.wedo.stream.cache.RedisCache" />
.....
</mapper>
实体类实现 Serializable
public class Sorter implements Serializable
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/spring-dao.xml","/applicationContext-cache.xml"})
@ActiveProfiles(value="dev")
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DbUnitTestExecutionListener.class })
public class CacheTest {
private static Logger LOGGER = LoggerFactory.getLogger(CacheTest.class);
@Autowired
private SorterMapper mapper;
@Test
public void test(){
Date start = new Date();
for(int i=0;i<100;i++){
mapper.getall();
}
Date end = new Date();
long duration = end.getTime()-start.getTime();
LOGGER.info(duration);
}
}
测试结果,如果打开二级缓存,用时363毫秒,如果关闭二级缓存用时6秒+,平均一次查询50毫秒。