Spring Boot缓存技术(ehcache、SpringData Redis)

  • SpringBoot 整合 Ehcache
  • SpringBoot 整合 SpringDataRedis

 
 
一、SpringBoot 整合 Ehcache
 
1、导入相关maven依赖

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.10.RELEASE</version>
	</parent>
	<groupId>com.bjsxt</groupId>
	<artifactId>23-spring-boot-ehcache</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<java.version>1.7</java.version>
		<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
		<thymeleaf-layout-dialect.version>2.0.4</thymeleaf-layout-dialect.version>
	</properties>

	<dependencies>
		<!-- springBoot的启动器 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!-- springBoot的启动器 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>

		<!-- springBoot的启动器 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>

		<!-- 测试工具的启动器 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
		</dependency>

		<!-- mysql -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>

		<!-- druid连接池 -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.0.9</version>
		</dependency>

		<!-- Spring Boot缓存支持启动器 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-cache</artifactId>
		</dependency>

		<!-- Ehcache坐标 -->
		<dependency>
			<groupId>net.sf.ehcache</groupId>
			<artifactId>ehcache</artifactId>
		</dependency>

	</dependencies>
</project>

 
2、创建 Ehcache 的配置文件

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">

    <diskStore path="java.io.tmpdir"/>

  <!--defaultCache:echcache的默认缓存策略  -->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            maxElementsOnDisk="10000000"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </defaultCache>
    <!-- 自定义缓存策略 -->
    <cache name="users"
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            maxElementsOnDisk="10000000"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </cache>
</ehcache>

 
3、修改 application.properties 文件

spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/ssm
spring.datasource.username=root
spring.datasource.password=root

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
#spring data 正向工程
spring.jpa.hibernate.ddl-auto=update
#显示sql
spring.jpa.show-sql=true

#配置ehcache
spring.cache.ehcache.cofnig=ehcache.xml

 
4、修改启动类,在启动类上面添加@EnableCaching

package com.bjsxt;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;


@SpringBootApplication
@EnableCaching
public class App {

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

 
5、创建业务层

package com.bjsxt.service;

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import com.bjsxt.pojo.Users;

public interface UsersService {
	
	List<Users> findUserAll();
	Users findUserById(Integer id);
	Page<Users> findUserByPage(Pageable pageable);
	void saveUsers(Users users);
}

package com.bjsxt.service.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import com.bjsxt.dao.UsersRepository;
import com.bjsxt.pojo.Users;
import com.bjsxt.service.UsersService;
/**
 * UsersService接口实现类
 *
 *
 */
@Service
public class UsersServiceImpl implements UsersService {

	@Autowired
	private UsersRepository usersRepository;
	
	@Override
	@Cacheable(value = "users")
	public List<Users> findUserAll() {
		return this.usersRepository.findAll();
	}

	@Override
	//@Cacheable:对当前查询的对象做缓存处理
	@Cacheable(value="users") //value对应自定义缓存策略的name
	public Users findUserById(Integer id) {
		return this.usersRepository.findOne(id);
	}

}

 
6、修改实体类

package com.bjsxt.pojo;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="t_users")
public class Users implements Serializable {

	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	@Column(name="id")
	private Integer id;
	
	@Column(name="name")
	private String name;
	
	@Column(name="age")
	private Integer age;
	
	@Column(name="address")
	private String address;
	

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	@Override
	public String toString() {
		return "Users [id=" + id + ", name=" + name + ", age=" + age + ", address=" + address + "]";
	}
}

 
7、测试

@Autowired
	private UsersService usersService;
	
	@Test
	public void testFindUserById(){
		//第一次查询
		System.out.println(this.usersService.findUserById(1));
		
		//第二次查询
		System.out.println(this.usersService.findUserById(1));
	}

 
 
二、@Cacheable 与@CacheEvict
 
1、@Cacheable
  @Cacheable 作用:把方法的返回值添加到 Ehcache 中做缓存
  Value 属性:指定一个 Ehcache 配置文件中的缓存策略,如果么有给定 value,name 则 表示使用默认的缓存策略

<!-- 自定义缓存策略 -->
    <cache name="users"
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            maxElementsOnDisk="10000000"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </cache>

  Key 属性:给存储的值起个名称。在查询时如果有名称相同的,那么则知己从缓存中将 数据返回
 
1.1、业务层

@Override
	@Cacheable(value = "users",key = "#pageable.pageSize")
	public Page<Users> findUserByPage(Pageable pageable) {
		return this.usersRepository.findAll(pageable);
	}

 
1.2、测试代码

@Test
	public void testFindUserByPage(){
		Pageable pageable=new PageRequest(0,2);
		//第一次查询
		System.out.println(this.usersService.findUserByPage(pageable).getTotalElements());
		//第二次查询
		System.out.println(this.usersService.findUserByPage(pageable).getTotalElements());
		//第三次查询
		pageable=new PageRequest(1,2);
		System.out.println(this.usersService.findUserByPage(pageable).getTotalElements());
	}

 
2、@CacheEvict
 
@CacheEvict 作用:清除缓存
 
2.1、业务层

package com.bjsxt.service.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import com.bjsxt.dao.UsersRepository;
import com.bjsxt.pojo.Users;
import com.bjsxt.service.UsersService;
/**
 * UsersService接口实现类
 *
 *
 */
@Service
public class UsersServiceImpl implements UsersService {

	@Autowired
	private UsersRepository usersRepository;
	
	@Override
	@Cacheable(value = "users")
	public List<Users> findUserAll() {
		return this.usersRepository.findAll();
	}

	@Override
	//@Cacheable:对当前查询的对象做缓存处理
	@Cacheable(value="users") //value对应自定义缓存策略的name
	public Users findUserById(Integer id) {
		return this.usersRepository.findOne(id);
	}

	@Override
	@Cacheable(value = "users",key = "#pageable.pageSize")
	public Page<Users> findUserByPage(Pageable pageable) {
		return this.usersRepository.findAll(pageable);
	}

	@Override
	@CacheEvict(value = "users",allEntries = true)//清除缓存中以users缓存策略缓存的对象
	public void saveUsers(Users users) {
		this.usersRepository.save(users);
	}

}

 
2.2、测试代码

@Test
	public void testFindAll(){
		//第一次查询
		System.out.println(usersService.findUserAll().size());
		Users users=new Users();
		users.setAddress("南京");
		users.setAge(43);
		users.setName("朱七");
		this.usersService.saveUsers(users);
		//第二次查询
		System.out.println(usersService.findUserAll().size());

	}

 
 
三、SpringBoot 整合 SpringDataRedis
 
Redis 版本:3.2.1
运行环境:windows
 
1、SpringBoot 整合 SpringDataRedis
 
  SpringDataRedis 是属于 SpringData 下的一个模块。作用就是简化对于 redis 的操作
 
1.1、修改 pom 文件添加 SpringDataRedis 的坐标

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.10.RELEASE</version>
  </parent>
  <groupId>com.bjsxt</groupId>
  <artifactId>24-spring-boot-redis</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <properties>
  <java.version>1.7</java.version>
  <thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
  <thymeleaf-layout-dialect.version>2.0.4</thymeleaf-layout-dialect.version>
  </properties>
  
  <dependencies>
  	<!-- springBoot的启动器 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- thymeleaf的启动器 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    
    <!-- Spring Data Redis的启动器 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

      <!-- 测试工具的启动器 -->
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
      </dependency>


  </dependencies>
</project>

 
1.2、编写 SpringDataRedis 的配置类(重点)

package com.bjsxt.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import redis.clients.jedis.JedisPoolConfig;

/**
 * 完成对Redis的整合的一些配置
 *
 *
 */
@Configuration
public class RedisConfig {

	/**
	 * 1.创建JedisPoolConfig对象。在该对象中完成一些链接池配置
	 *	@ConfigurationProperties:会将前缀相同的内容创建一个实体
	 */
	@Bean
	@ConfigurationProperties(prefix = "spring.redis.pool")
	public JedisPoolConfig jedisPoolConfig(){
		JedisPoolConfig config = new JedisPoolConfig();
		//最大空闲数
		config.setMaxIdle(10);
		//最小空闲数
		config.setMinIdle(5);
		//最大链接数
		config.setMaxTotal(20);
		System.out.println("默认值"+config.getMaxIdle());
		System.out.println("默认值"+config.getMinIdle());
		System.out.println("默认值"+config.getMaxTotal());
		return config;
	}
	
	/**
	 * 2.创建JedisConnectionFactory:配置redis链接信息
	 */
	@Bean
	@ConfigurationProperties(prefix = "spring.redis")
	public JedisConnectionFactory jedisConnectionFactory(JedisPoolConfig config){
		System.out.println("配置完毕"+config.getMaxIdle());
		System.out.println("配置完毕"+config.getMinIdle());
		System.out.println("配置完毕"+config.getMaxTotal());
		JedisConnectionFactory factory = new JedisConnectionFactory();
		//关联链接池的配置对象
		factory.setPoolConfig(config);
		//配置链接Redis的信息
		//主机地址
		factory.setHostName("127.0.0.1");
		//端口
		factory.setPort(6379);
		
		return factory;
	}
	
	/**
	 * 3.创建RedisTemplate:用于执行Redis操作的方法
	 */
	@Bean
	public RedisTemplate<String,Object> redisTemplate(JedisConnectionFactory factory){
		RedisTemplate<String, Object> template = new RedisTemplate<>();
		//关联
		template.setConnectionFactory(factory);
		
		//为key设置序列化器
		template.setKeySerializer(new StringRedisSerializer());
		//为value设置序列化器
		template.setValueSerializer(new StringRedisSerializer());
		
		return template;
	}
}

 
1.3、编写测试代码,测试整合环境
 
  1.3.1、编写测试类

	@Autowired
    private RedisTemplate<String,Object> redisTemplate;

    //添加一个字符串
    @Test
    public void testSet(){
        this.redisTemplate.opsForValue().set("key","青衫");
    }

    //取出一个字符串
    @Test
    public void testGet(){
        String value= (String) this.redisTemplate.opsForValue().get("key");
        System.out.println(value);
    }

 
2、提取 redis 的配置信息
 
2.1、在 src/main/resource/ 目录下新建一个配置文件:application.properties

#最大空闲数
spring.redis.pool.max-idle=10
#最小空闲数
spring.redis.pool.min-idle=5
#最大链接数
spring.redis.pool.max-total=20
#主机ip
spring.redis.host=127.0.0.1
#redis端口
spring.redis.port=6379

 
2.2、修改redis配置类

package com.bjsxt.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import redis.clients.jedis.JedisPoolConfig;

/**
 * 完成对Redis的整合的一些配置
 *
 *
 */
@Configuration
public class RedisConfig {

	/**
	 * 1.创建JedisPoolConfig对象。在该对象中完成一些链接池配置
	 *	@ConfigurationProperties:会将前缀相同的内容创建一个实体
	 */
	@Bean
	@ConfigurationProperties(prefix = "spring.redis.pool")
	public JedisPoolConfig jedisPoolConfig(){
		JedisPoolConfig config = new JedisPoolConfig();
		System.out.println("默认值"+config.getMaxIdle());
		System.out.println("默认值"+config.getMinIdle());
		System.out.println("默认值"+config.getMaxTotal());
		return config;
	}
	
	/**
	 * 2.创建JedisConnectionFactory:配置redis链接信息
	 */
	@Bean
	@ConfigurationProperties(prefix = "spring.redis")
	public JedisConnectionFactory jedisConnectionFactory(JedisPoolConfig config){
		System.out.println("配置完毕"+config.getMaxIdle());
		System.out.println("配置完毕"+config.getMinIdle());
		System.out.println("配置完毕"+config.getMaxTotal());
		JedisConnectionFactory factory = new JedisConnectionFactory();
		//关联链接池的配置对象
		factory.setPoolConfig(config);
		return factory;
	}
	
	/**
	 * 3.创建RedisTemplate:用于执行Redis操作的方法
	 */
	@Bean
	public RedisTemplate<String,Object> redisTemplate(JedisConnectionFactory factory){
		RedisTemplate<String, Object> template = new RedisTemplate<>();
		//关联
		template.setConnectionFactory(factory);
		
		//为key设置序列化器
		template.setKeySerializer(new StringRedisSerializer());
		//为value设置序列化器
		template.setValueSerializer(new StringRedisSerializer());
		
		return template;
	}
}

 
3、SpringDataRedis 操作实体对象
 
  3.1.1、创建实体类

/**
 * Copyright (C), 2015-2019, XXX有限公司
 * FileName: Users
 * Author:   admin
 * Date:     2019/5/24 11:25
 * Description:
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.bjsxt.pojo;

import java.io.Serializable;

/**
 * 〈一句话功能简述〉<br> 
 * 〈〉
 *
 * @author admin
 * @create 2019/5/24
 * @since 1.0.0
 */
public class Users implements Serializable {

    private Integer id;
    private String name;
    private Integer age;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("Users{");
        sb.append("id=").append(id);
        sb.append(", name='").append(name).append('\'');
        sb.append(", age=").append(age);
        sb.append('}');
        return sb.toString();
    }
}

 
3.1.2、测试代码

/**
     * 添加一个Users对象
     */
    @Test
    public void testSetUsers(){
        Users users=new Users();
        users.setAge(20);
        users.setName("张三丰");
        users.setId(1);
        //存的时候,要重新设置序列化器
        this.redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        this.redisTemplate.opsForValue().set("users",users);

    }

    /**
     * 取Users对象
     */
    @Test
    public void testGetUsers(){
        //取的操作,必须重新设置序列化器
        this.redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        Users users= (Users) this.redisTemplate.opsForValue().get("users");
        System.out.println(users);
    }

 
4、SpringDataRedis 以 JSON 格式存储实体对象
 
  4.1、测试代码

/**
     * 基于JSON格式存Users对象
     */
    @Test
    public void testSetUsersUseJSON(){
        Users users=new Users();
        users.setAge(20);
        users.setName("李四丰");
        users.setId(1);

        this.redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Users.class));
        this.redisTemplate.opsForValue().set("users_json",users);

    }
    /**
     * 基于JSON格式取Users对象
     */
    @Test
    public void testGetUseJSON(){
        //反序列化
        this.redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Users.class));
        Users users= (Users) this.redisTemplate.opsForValue().get("users_json");
        System.out.println(users);
    }
上一篇:什么是 redis 的雪崩、穿透和击穿?


下一篇:使用spring cache和ehcache