1. 程式人生 > >Redis快取配置及使用

Redis快取配置及使用

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
[email protected]$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 =