springboot整合redis做緩存管理----一步步構建詳解

Redis安裝

     Redis 是完全開源免費的,遵守BSD協議,是一個高性能的key-value數據庫。

     Redis 與其他 key - value 緩存產品有以下三個特點:

  •        Redis支持數據的持久化,可以將內存中的數據保存在磁盤中,重啓的時候可以再次加載進行使用。
  •        Redis不僅僅支持簡單的key-value類型的數據,同時還提供list,set,zset,hash等數據結構的存儲。
  •        Redis支持數據的備份,即master-slave模式的數據備份。

    redis安裝傳送門

pom.xml依賴

<dependencies>
		<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>
		
		<dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
		
		<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
		
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        
        <dependency>        
		    <groupId>com.fasterxml.jackson.core</groupId>
		    <artifactId>jackson-annotations</artifactId>
		</dependency>
		
		<dependency>
		    <groupId>com.alibaba</groupId>
		    <artifactId>druid-spring-boot-starter</artifactId>
		    <version>1.1.10</version>
		</dependency>
			
		<dependency>
	        <groupId>org.springframework.boot</groupId>
	        <artifactId>spring-boot-devtools</artifactId>
	        <optional>true</optional>
	    </dependency>
	</dependencies>

application.yml配置

server:
  port: 8080
  
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/dycai?useUnicode=true&characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false
    username: root
    password: "088114"
  redis:
    host: localhost
    port: 6379
    password: 
    database: 0

mybatis:
  mapper-locations: classpath:mapper/*.xml

使用redis做緩存配置

配置部分主要是配置緩存管理器CacheManager 和RedisTemplate

Redis採用key-value存儲的存儲方式,對key和value需要序列化,常用四種序列化器StringRedisSerializer、JdkSerializationRedisSerializer、Jackson2JsonRedisSerializer、GenericJackson2JsonRedisSerializer的詳細介紹如下:

1、StringRedisSerializer:

      優點:開發者友好,輕量級,效率也比較高
                 缺點:只能序列化String類型,如果key使用該序列化器,則key必須爲String類型

2、jdkSerializationRedisSerializer:RestTemplate類默認的序列化方式,如果指定序列化器,則爲它
                優點:反序列化時不需要提供類型信息(class)
                缺點:a、首先它要求存儲的對象都必須實現java.io.Serializable接口,比較笨重
                          b、其次,他存儲的爲二進制數據,這對開發者是不友好的,無法直觀查看數據
                          c、序列化後的結果非常龐大,是JSON格式的5倍左右,這樣就會消耗redis服務器的大量內存。  

3、Jackson2JsonRedisSerializer:把一個對象以Json的形式存儲,效率高且對調用者友好
                 優點:速度快,序列化後的字符串短小精悍,不需要存儲對象實現java.io.Serializable接口
                 缺點:那就是此類的構造函數中有一個類型參數,必須提供要序列化對象的類型信息(.class對象),反序列化用到了該                              類型信息 

4、GenericJackson2JsonRedisSerializer:基本和上面的Jackson2JsonRedisSerializer功能差不多,使用方式也差不多,但不需要提供類型信息,推薦使用;

以上四種序列化方式如何配置見下面的代碼片段,下面的代碼片段採用的是StringRedisSerializer序列化key,GenericJackson2JsonRedisSerializer序列化value;

@Configuration
@EnableCaching
public class CacheConfig{
	/**
	 * 配置緩存管理器RedisCacheManager
	 * Redis採用key-value存儲的存儲方式,對key和value需要序列化
	 * Redis的序列化方式由StringRedisSerializer,JdkSerializationRedisSerializer,GenericJackson2JsonRedisSerializer,GenericJackson2JsonRedisSerializer等
	 * RedisCacheManager默認採用StringRedisSerializer序列化key,JdkSerializationRedisSerializer序列化value
	 * @param redisConnectionFactory
	 * @return
	 */
	@Bean
	public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
//		StringRedisSerializer序列器:
//		優點:開發者友好,輕量級,效率也比較高
//		缺點:只能序列化String類型,如果key使用該序列化器,則key必須爲String類型
		RedisSerializer<String> redisSerializer = new StringRedisSerializer();
		
//		jdkSerializationRedisSerializer序列化器:RestTemplate類默認的序列化方式,如果指定序列化器,則爲它
//		優點:反序列化時不需要提供類型信息(class)
//		缺點:1、首先它要求存儲的對象都必須實現java.io.Serializable接口,比較笨重
//			  2、其次,他存儲的爲二進制數據,這對開發者是不友好的
//			  3、序列化後的結果非常龐大,是JSON格式的5倍左右,這樣就會消耗redis服務器的大量內存。		
//		ClassLoader loader = this.getClass().getClassLoader();
//		JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer(loader);
		
//		Jackson2JsonRedisSerializer序列化器:把一個對象以Json的形式存儲,效率高且對調用者友好
//		優點:速度快,序列化後的字符串短小精悍,不需要存儲對象實現java.io.Serializable接口
//		缺點:那就是此類的構造函數中有一個類型參數,必須提供要序列化對象的類型信息(.class對象),反序列化用到了該類型信息
//		Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
//		ObjectMapper objectMapper = new ObjectMapper();
//		objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
		
//		GenericJackson2JsonRedisSerializer序列化器:基本和上面的Jackson2JsonRedisSerializer功能差不多,使用方式也差不多,
//		但不需要提供類型信息,推薦使用
		GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
		RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
				.entryTtl(Duration.ofMinutes(10))	//設置失效時間
				.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
				.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(genericJackson2JsonRedisSerializer));
		
		RedisCacheManager redisCacheManager = RedisCacheManager.builder(redisConnectionFactory)
				.cacheDefaults(config)
				.build();
		
		return redisCacheManager;
	}
	
	@Bean
	public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
		RedisTemplate<String, Object> template = new RedisTemplate<>();
		template.setConnectionFactory(redisConnectionFactory);
		GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();		
		template.setKeySerializer(new StringRedisSerializer());
		template.setValueSerializer(genericJackson2JsonRedisSerializer);		
		template.setHashKeySerializer(new StringRedisSerializer());
		template.setHashValueSerializer(genericJackson2JsonRedisSerializer);
		template.afterPropertiesSet();
		return template;
	}
}

實列

代碼結構如下

UserController.java

package cn.cai.microservice.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import cn.cai.microservice.entiy.User;
import cn.cai.microservice.service.UserService;

@RestController
public class UserController {	
	private static final Logger log = LoggerFactory.getLogger(UserController.class);
	@Autowired
	private UserService userService;
	
	@PostMapping("/get/UserInfo/{userName}")
	public User getUserInfoByName(@PathVariable(value="userName") String userName) {
		long startTime = System.currentTimeMillis();
		User user =  userService.getUserInfoByName(userName);
		log.info("查詢耗時:" + (System.currentTimeMillis() - startTime) + "ms");
		return user;
	}
	
	@PostMapping("/update/UserInfo")
	public void updateUserInfo(@RequestBody User user) {
		userService.updateUserInfo(user);
	}
	
	@PostMapping("/delete/userInfo/{userName}")
	public void deleteUserInfo(@PathVariable(value="userName") String userName) {
		userService.deleteUserInfo(userName);
	}
	
	@PostMapping("/insert/UserInfo")
	public void insertUserInfo(@RequestBody User user) {
		userService.insertUserInfo(user);
	}
	
}

UserDao.java

package cn.cai.microservice.dao;

import cn.cai.microservice.entiy.User;

public interface UserDao {
	User getUserInfoByName(String userName);
	
	void updateUserInfo(User user);
	
	void deleteUserInfo(String userName);
	
	void insertUserInfo(User user);
}

User.java

package cn.cai.microservice.entiy;

import java.io.Serializable;

//如果採用的是JdkSerializationRedisSerializer序列化器序列化value,則存儲對象必須實現Serializable接口
//其他序列化器,可以不實現
public class User implements Serializable{

	private static final long serialVersionUID = 1L;
	private String userName;
	private String password;
	private String email;
	
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	@Override
	public String toString() {
		return "User [userName=" + userName + ", password=" + password + ", email=" + email + "]";
	}
}

UserService.java

     Spring提供緩存註解@Cacheable、@CacheEvict、@CachePut

     @Cacheable:如果緩存之中能夠查找到,就不執行該註解下面的方法,如果找不到,就執行方法,將方法的返回結果作爲value防止到緩存中;

     @CachePut:不管緩存之中能否查找到,該註解下的方法都會被執行,且用返回結果作爲value更新緩存

     @CachePut:刪除指定key的緩存 

package cn.cai.microservice.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 cn.cai.microservice.dao.UserDao;
import cn.cai.microservice.entiy.User;

@Service
public class UserService {
	private static final Logger log = LoggerFactory.getLogger(UserService.class);	
	@Autowired
	private UserDao userDao;	
	
//	註解@Cacheable:如果緩存之中能夠查找到,就不執行該註解下面的方法;
//	如果找不到,就執行方法,將方法的返回結果作爲value防止到緩存中;
	@Cacheable(value="userInfoCache", key="#userName")
	public User getUserInfoByName(String userName) {
		log.info("查詢" + userName + "信息");
		User user = userDao.getUserInfoByName(userName);
		return user;
	}

//	註解@CachePut:不管緩存之中能否查找到,該註解下的方法都會被執行,且用返回結果作爲value更新緩存
	@CachePut(value="userInfoCache", key="#user.userName")
	public User updateUserInfo(User user) {
		log.info("更新" + user.getUserName() + "信息");
		userDao.updateUserInfo(user);	
		return user;
	}

//	註解@CachePut:刪除指定key的緩存 
	@CacheEvict(value="userInfoCache", key="#userName")
	public void deleteUserInfo(String userName) {
		log.info("刪除" + userName + "信息");
		userDao.deleteUserInfo(userName);	
	}
	
	@CachePut(value="userInfoCache", key="#user.userName")
	public User insertUserInfo(User user) {
		userDao.insertUserInfo(user);
		return user;
	}
	
}

UserMapper.xml

<?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="cn.cai.microservice.dao.UserDao">

	<select id="getUserInfoByName" resultType="cn.cai.microservice.entiy.User">
		select * from userInfo where userName=#{userName}
	</select>
	
	<update id="updateUserInfo">
		update userInfo set
			password=#{password},
			email=#{email}
		where userName=#{userName} 
	</update>

	<delete id="deleteUserInfo">
		delete from userInfo where userName=#{userName}
	</delete>
	
	<insert id="insertUserInfo">
		insert into 
			userInfo(userName, password, email) values(#{userName}, #{password}, #{email})
	</insert>
</mapper>

SpringbootRedisCacheApplication.java

package cn.cai.microservice;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan({"cn.cai.microservice.dao"})
public class SpringbootRedisCacheApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringbootRedisCacheApplication.class, args);
	}

}

項目源碼下載地址:https://github.com/xdouya/springboot-redis-cache

當時調試的時候遇到了很多坑,如有疑問,留言交流。

如果覺得有用,請記得給顆星星哦!

參考:https://www.runoob.com/redis/redis-intro.html

           https://blog.csdn.net/f641385712/article/details/84679456

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章