Redis缓存配置及使用

版权声明:From Lay https://blog.csdn.net/Sadlay/article/details/83821668

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;
    }
}

猜你喜欢

转载自blog.csdn.net/Sadlay/article/details/83821668