Spring Boot整合Redis缓存
Maven依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<!-- 不依赖redis的异步客户端 lettuce -->
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 引入Redis的客户端驱动jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!-- dbcp2连接池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
</dependency>
<!-- mabatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- fastJson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastJson</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
缓存管理器配置
# redis缓存管理配置
#设置缓存类型位redis
spring.cache.type=redis
#配置缓存名称
spring.cache.cache-names=redisCache
#是否允许redis缓存空值
spring.cache.redis.cache-null-values=true
#redis的键前缀
spring.cache.redis.key.prefix=
#缓存超时时间戳,配置为0则不设置超时时间
spring.cache.redis.time-to-live=0ms
#是否启用redis的键前缀
spring.cache.redis.use-key-preficx=true
这里我们只需要配置两个
# redis缓存管理配置
spring.cache.type=redis
spring.cache.cache-names=redisCache
启用缓存机制
添加注解@EnableCaching
package com.lay.redis;
@SpringBootApplication
@MapperScan(basePackages = "com.lay.redis", annotationClass = Mapper.class)
@EnableCaching
public class SpringbootRedisApplication {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(SpringbootRedisApplication.class, args);
}
这样就能驱动缓存机制了。
下面我们整合mybatis框架来测试缓存机制的使用
搭建环境
配置文件
#数据库配置
spring.datasource.url=jdbc:mysql://192.168.0.106:3306/springboot_database?useUnicode=true&characterEncoding=utf8
spring.datasource.username=developer
spring.datasource.password=1q@W3e$R
# spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#指定数据连接池的类型
spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource
#最大等待连接中的数量,设置0为没有限
spring.datasource.dbcp2.max-idle=10
#最大连接活动数
spring.datasource.dbcp2.max-total=50
#最大等待毫秒数,单位ms,超过时间会出错误信息
spring.datasource.dbcp2.max-wait-millis=10000
#数据库连接池初始化连接数
spring.datasource.dbcp2.initial-size=5
#设置默认的隔离级别为读写提交
spring.datasource.dbcp2.default-transaction-isolation=2
# mybatis配置
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package: com.lay.redis.entity
# 配置typehandler类型转换的扫描包
mybatis.type-handlers-package=com.lay.redis.typehandler
#驼峰命名转换
mybatis.configuration.mapUnderscoreToCamelCase=true
# 配置redis连接池属性
spring.redis.jedis.pool.max-active=10
spring.redis.jedis.pool.max-idle=10
spring.redis.jedis.pool.max-wait=2000
spring.redis.jedis.pool.min-idle=5
#配置redis服务器属性
spring.redis.port=6379
spring.redis.host=192.168.0.106
spring.redis.password=123456
#redis连接超时时间
spring.redis.timeout=1000
#springmvc字符集
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true
# redis缓存管理配置
spring.cache.type=redis
spring.cache.cache-names=redisCache
#日志级别
logging.level.root=debug
logging.level.org.springframework=debug
logging.level.org.org.org.mybatis=debug
用户实体
package com.lay.redis.entity;
import java.io.Serializable;
import org.apache.ibatis.type.Alias;
import com.lay.redis.enumeration.SexEnum;
@Alias("person")
public class Person implements Serializable {
private static final long serialVersionUID = 3172000990909338544L;
private Long id = null;
private String personName = null;
//性别枚举,这里需要使用typeHandler进行转换
private SexEnum sex = null;//枚举
private String note = null;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public SexEnum getSex() {
return sex;
}
public void setSex(SexEnum sex) {
this.sex = sex;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
public String getPersonName() {
return personName;
}
public void setPersonName(String personName) {
this.personName = personName;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
}
mybatis操作接口
package com.lay.redis.dao;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.lay.redis.entity.Person;
@Mapper
public interface PersonDao {
//获取单个用户
public Person getPerson(Long id);
//新增用户
public int insertPerson(Person person);
//更新用户
public int updatePerson(Person person);
//获取全部用户
public List<Person> getAllPersons();
//删除用户
public int deletePerson(Long id);
}
sql和映射关系mapper
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lay.redis.dao.PersonDao">
<select id="getPerson" parameterType="long" resultType="person">
select id,person_name,sex,note from t_person where id=#{id}
</select>
<insert id="insertPerson" useGeneratedKeys="true" keyProperty="id" >
insert into t_person(person_name,sex,note) values(#{personName},#{sex},#{note})
</insert>
<update id="updatePerson">
update t_person
<set>
<if test="personName!=null">person_name=#{personName},</if>
<if test="sex!=null">sex=#{sex},</if>
<if test="note!=null">note=#{note}</if>
</set>
where id=#{id}
</update>
<select id="getAllPersons" resultType="person">
select id,person_name,sex,note from t_person
</select>
<delete id="deletePerson" parameterType="long">
delete from t_person where id=#{id}
</delete>
</mapper>
服务层Service
package com.lay.redis.service;
import java.util.List;
import com.lay.redis.entity.Person;
public interface PersonService {
//获取单个用户
public Person getPerson(Long id);
//新增用户
public Person insertPerson(Person person);
//更新用户名
public Person updatePerson(Long id, String personName);
//获取全部用户
public List<Person> getAllPersons();
//删除用户
public int deletePerson(Long id);
}
服务层实现
package com.lay.redis.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.lay.redis.dao.PersonDao;
import com.lay.redis.entity.Person;
import com.lay.redis.service.PersonService;
@Service
public class PersonServiceImpl implements PersonService {
@Autowired
PersonDao personDao;
//获取id,取参数id缓存用户
@Override
@Transactional
@Cacheable(value = "redisCache", key = "'redis_person_'+#id")
public Person getPerson(Long id) {
return personDao.getPerson(id);
}
//插入用户,最后mybatis会回填id,取结果id缓存用户
@Override
@Transactional(isolation = Isolation.READ_COMMITTED, timeout = 1, propagation = Propagation.REQUIRES_NEW)
@CachePut(value = "redisCache", key = "'redis_person_'+#result.id")
public Person insertPerson(Person person) {
System.out.println("===========sex==========" + person.getSex().getId());
personDao.insertPerson(person);
return person;
}
//更新数据后,更新缓存,如果condition配置项使结果返回为Null,不缓存
@Override
@Transactional
@CachePut(value = "redisCache", condition = "#result!='null'", key = "'redis_person_'+#id")
public Person updatePerson(Long id, String personName) {
Person person = this.getPerson(id);
if (person == null) {
return null;
}
person.setPersonName(personName);
personDao.updatePerson(person);
return person;
}
@Override
public List<Person> getAllPersons() {
return personDao.getAllPersons();
}
//移除缓存
@Override
@Transactional
@CacheEvict(value = "redisCache", key = "'redis_person_'+#id", beforeInvocation = false)
public int deletePerson(Long id) {
return personDao.deletePerson(id);
}
}
- @CachePut:将方法结果返回存放到缓存中
- @Cacheable:先从缓存中通过定义的键查询,如果可以查到数据,则返回,否则执行该方法,返回数据,并且将返回的结果保存到缓存中。
- @CacheEvict:通过定义的键移除缓存,它有一个boolean类型的配置项
beforeInvocation
,表示在方法之前或者之后移除缓存。默认是false
,所以默认为方法之后将缓存移除。
value="redisCache"与在spring配置文件中的缓存名称对应,这样就能够引用到对应的缓存中去了。
测试缓存注解
package com.lay.redis.controller;
@Controller
@RequestMapping(value = "/person")
public class PersonController {
@Autowired
PersonService personService;
@RequestMapping(value = "/getPerson")
@ResponseBody
public Person getPerson(@RequestParam("id") Long id) {
return personService.getPerson(id);
}
@RequestMapping(value = "/insertPerson")
@ResponseBody
public Person inserPerson(String personName, String sex, String note) {
Person person = new Person();
person.setPersonName(personName);
person.setSex(SexEnum.getEnumByName(sex));
person.setNote(note);
personService.insertPerson(person);
return person;
}
@RequestMapping(value = "/updatePersonName")
@ResponseBody
public Map<String, Object> updatePerson(Long id, String personName) {
Person person = personService.updatePerson(id, personName);
boolean flag = person != null;
String message = flag ? "更新成功" : "更新失败";
return resultMap(flag, message);
}
@RequestMapping(value = "/getAllPerson")
@ResponseBody
public List<Person> getAllPerson() {
return personService.getAllPersons();
}
@RequestMapping(value = "/deletePerson")
@ResponseBody
public Map<String, Object> inserPerson(Long id) {
int result = personService.deletePerson(id);
boolean flag = result == 1;
String message = flag ? "更新成功" : "更新失败";
return resultMap(flag, message);
}
private Map<String, Object> resultMap(boolean success, String message) {
Map<String, Object> result = new HashMap<String, Object>();
result.put("success", success);
result.put("message", message);
return result;
}
}
自定义缓存序列化方式
redis默认缓存为jdkserialize,我们改成熟悉的json
引入阿里巴巴的fastjson
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastJson</artifactId>
<version>1.2.17</version>
</dependency>
实现redis缓存序列化方式
package com.lay.redis.utils;
/**
* 自定义redis缓存序列化方式
* @Description TODO
* @ClassName FastJsonRedisSerializer
* @Date 2018年11月4日 下午9:51:25
* @Author lay
*/
public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private Class<T> clazz;
public FastJsonRedisSerializer(Class<T> clazz) {
super();
this.clazz = clazz;
}
@Override
public byte[] serialize(T t) throws SerializationException {
if (t == null) {
return new byte[0];
}
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
}
@Override
public T deserialize(byte[] bytes) throws SerializationException {
if (bytes == null || bytes.length <= 0) {
return null;
}
String str = new String(bytes, DEFAULT_CHARSET);
return JSON.parseObject(str, clazz);
}
}
通过RedisCacheConfig配置
package com.lay.redis.config;
/**
* redis 缓存配置
* @Description TODO
* @ClassName RedisCacheConfig
* @Date 2018年11月4日 下午10:18:40
* @Author lay
*/
@Configuration
public class RedisCacheConfig extends CachingConfigurerSupport {
/**
* 设置 redis 缓存数据默认过期时间
* 设置@cacheable 序列化方式
* @return
* @Date 2018年11月4日 下午10:10:11
* @Author lay
*/
//@Bean
public RedisCacheConfiguration redisCacheConfiguration() {
FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer))
.entryTtl(Duration.ofDays(30));
return configuration;
}
}
自定义缓存管理器
如果不想用Spring Boot机制带来的键名命名方式,也不希望缓存永远不超时,我们可以自定义缓存管理器。
方式一:properties文件配置
# redis缓存管理配置
#设置缓存类型位redis
spring.cache.type=redis
#禁用前缀
spring.cache.redis.use-key.prefix= false
#自定义前缀
spring.cache.redis.key-preficx=...
#定义超时时间,单位毫秒
spring.cache.redis.time-to-live=60000
方式二:java配置
配置之前properties文件的缓存管理器配置
package com.lay.redis.config;
/**
* redis 缓存配置
* @Description TODO
* @ClassName RedisCacheConfig
* @Date 2018年11月4日 下午10:18:40
* @Author lay
*/
@Configuration
public class RedisCacheConfig extends CachingConfigurerSupport {
//自定义redis缓存管理器
//@Bean(name = "redisCacheManager")
public RedisCacheManager initRedisCacheManager(RedisConnectionFactory connectionFactory) {
//Redis加锁的写入器
RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(connectionFactory);
//启动Redis缓存的默认设置
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
//设置序列化器,这里为jdk
config = config.serializeValuesWith(SerializationPair.fromSerializer(new JdkSerializationRedisSerializer()));
//禁用前缀
config = config.disableKeyPrefix();
//设置10分钟超时
config = config.entryTtl(Duration.ofMinutes(10));
//创建redis缓存管理器
RedisCacheManager redisCacheManager = new RedisCacheManager(writer, config);
return redisCacheManager;
}
}