springboot2.x整合redis做缓存案例

前言

我们在开发后台系统,在前台需要展示报表数据时一般是通过调用后台数据接口,数据接口就去按条件查询数据库并将结果返回给前台人员。通常在数据表数据较少时,查询效率是可以的,然而一般在高用户量系统中数据库数据量是十分庞大的,通过数据表建立索引虽然能够加快查询效率,但是速度还是会显得缓慢。这时我们就可以考虑使用集群、分布式和缓存等后端技术进行解决。下面我就介绍一种常用的缓存中间件Redis,我们项目结合redis作缓存做一个简单的demo。当然其实还有其他主流的缓存中间件,如MemCached,有新兴趣的朋友可以去网上找资料。

整合代码

如果只想知道整合方式,那可以看完这节就可以了,有兴趣的朋友可以跟着继续看下去。

import com.hui.pojo.Department;
import com.hui.pojo.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class RedisConfig extends CachingConfigurerSupport {
    @Autowired
    private RedisConnectionFactory redisConnectionFactory;
    /**
     * 缓存key生成规则,可自己定义
     * @return
     */
    @Bean(name = "empKeyGen")
    public KeyGenerator empkeyGenerator() {
    	//java8+写法 
        return (target, method, params) -> {
            StringBuilder sb = new StringBuilder();
            sb.append("emp-");
            sb.append(params[0]);
            return sb.toString();
        };
    }

    @Bean(name = "deptKeyGen")
    public KeyGenerator deptkeyGenerator() {
        return (target, method, params) -> {
            StringBuilder sb = new StringBuilder();
            sb.append("dept-");
            sb.append(params[0]);
            return sb.toString();
        };
    }

    /**
     * 我这里定义了两个cacheManager(缓存管理器),然后第一个缓存管理器创建了两个Cache,
     * 分别用于缓存员工和部门,并且两个Cache各自有自己的json序列化方式,
     * 大家也可以只用一个json序列化类,将泛型具体类改成Object就行
     * @return
     */
    @Bean(name = "cacheManager")
    @Primary
    public CacheManager CacheManager() {
        //配置value序列化
        Jackson2JsonRedisSerializer serializer1 = new Jackson2JsonRedisSerializer(Employee.class);
        Jackson2JsonRedisSerializer serializer2 = new Jackson2JsonRedisSerializer(Department.class);
        RedisCacheConfiguration config1 = RedisCacheConfiguration.defaultCacheConfig()
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer1));
        RedisCacheConfiguration config2 = RedisCacheConfiguration.defaultCacheConfig()
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer2));

        // 配置多个cache(缓存空间),每个缓存空间对应不同的配置(这里只做序列化区分设置)
        Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
        configMap.put("emp", config1);
        configMap.put("dept", config2);
        RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory)
                .withInitialCacheConfigurations(configMap)
                .build();
        return cacheManager;
    }

    /**
     * 自定义cacheManager2,此案例没有用到,只用作区分,可以删除
     * @return
     */
    @Bean(name="otherCacheManager")
    public CacheManager deptCacheManager() {
        Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(String.class);
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer));
        RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(redisCacheConfiguration).build();
        return cacheManager;
    }
}

项目搭建

  1. 创建springboot项目,导入需要用到的maven包
<dependencies>
		<!--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-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.1.1</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
	</dependencies>

  1. 数据库搭建

(1)员工表 emp

CREATE TABLE `emp` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `sex` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

(2)部门表 dept

CREATE TABLE `dept` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

3.创建相关包和类(service、pojo、mapper、controller)
(1)实体类

@Data
public class Employee implements Serializable {
    private Integer id;
    private String name;
    private String sex;
    private Integer age;
}

@Data
public class Department {
    private Integer id;
    private String name;
}

(2) mapper

@Mapper
public interface EmpMapper {

    @Select("select * from emp where id = #{id}")
    Employee findEmpById(Integer id);

    @Update("update emp set name=#{name},age=#{age} where id=#{id}")
    int updateEmp(Employee e);

    @Delete("delete from emp where id=#{id}")
    int delEmpById(Integer id);

}

@Mapper
public interface DeptMapper {

    @Select("select * from dept where id=#{id}")
    Department findById(Integer id);

    @Update("update dept set name=#{name} where id=#{id}")
    int updateDept(Department dept);

    @Delete("delete from dept where id=#{id}")
    int delDept(Integer id);
}

(3) service

@Service
@CacheConfig(cacheManager = "cacheManager", cacheNames = "dept", keyGenerator = "deptKeyGen")
public class DeptService {

    @Autowired
    private DeptMapper deptMapper;

    @Cacheable
    public Department findById(Integer id) {
        System.out.println("数据库操作查找部门");
        return deptMapper.findById(id);
    }

    @CachePut
    public Department updateDept(Department dept) {
        System.out.println("数据库操作更新部门");
        int row = deptMapper.updateDept(dept);
        if (row > 0) {
            return dept;
        } else {
            return null;
        }
    }

    @CacheEvict
    public int delDept(Integer id) {
        System.out.println("数据库操作删除部门");
        return deptMapper.delDept(id);
    }
}
@CacheConfig(cacheManager = "cacheManager", cacheNames = "emp", keyGenerator = "empKeyGen")
@Service
public class EmpService {

    @Autowired
    private EmpMapper empMapper;

    @Cacheable()
    public Employee findEmpById(Integer id) {
        System.out.println("数据库查找用户");
        Employee emp = empMapper.findEmpById(id);
        return emp;
    }

    @CachePut
    public Employee updateEmp(Employee e) {
        System.out.println("数据库更新用户");
        int row = empMapper.updateEmp(e);
        if (row > 0) {
            return e;
        } else {
          return null;
        }
    }
    @CacheEvict
    public int delEmpById(Integer id) {
        int res = empMapper.delEmpById(id);
        return res;
    }
}

(4) controller

@RestController
public class TestController {

    @Autowired
    private EmpService empService;
    @Autowired
    private DeptService deptService;

    @RequestMapping("/emp/{id}")
    public Employee getEmpById(@PathVariable("id") int id) {
        return empService.findEmpById(id);
    }

    @RequestMapping("/updateEmp")
    public Employee updateEmp(int id, String name,int age) {
        Employee e = new Employee();
        e.setAge(age);
        e.setId(id);
        e.setName(name);
        Employee emp = empService.updateEmp(e);
        return emp;
    }

    @RequestMapping("/delemp/{id}")
    public String delEmpById(@PathVariable("id") int id) {
        if (empService.delEmpById(id) > 0) {
            return "del success";
        } else {
            return "del fail";
        }
    }

    @RequestMapping("/dept/{id}")
    public Department getDeptById(@PathVariable("id") int id) {
        return deptService.findById(id);
    }

    @RequestMapping("/updateDept")
    public Department updateDept(int id, String name) {
        Department d = new Department();
        d.setId(id);
        d.setName(name);
        Department dept = deptService.updateDept(d);
        return dept;
    }

    @RequestMapping("/delDept/{id}")
    public String delDeptById(@PathVariable("id") int id) {
        if (deptService.delDept(id) > 0) {
            return "del success";
        } else {
            return "del fail";
        }
    }
}

一些知识补充

JSR107缓存规则

springboot是自带缓存功能的(实现了JSR107规范)实现,但是它好像是直接将缓存数据存在类似hashMap的一个地方,这样并不安全。我们整合redis作缓存,大家知道redis是一个高性能的内存数据库,就将相当于将缓存数据存在内存中,其速度肯定是快。下面图是JSR107规范图和解析:

1.CachingProvider定义了创建、配置、获取、管理和控制多个CacheManager。一个应用可以在运行期访问多个CachingProvider。
2.CacheManager定义了创建、配置、获取、管理和控制多个唯一命名的Cache,这些Cache存在于 CacheManager的上下文中。一个CacheManager仅被一个CachingProvider所拥有。
3. Cache是一个类似Map的数据结构并临时存储以Key为索引的值。一个Cache仅被一个CacheManager所拥有。
4.Entry是一个存储在Cache中的key-value对.
5.Expiry:每一个存储在Cache中的条目有一个定义的有效期。一旦超过这个时间,条目为过期的状态。一旦过期,条目将不可访问、更新和删除。缓存有效期可以通过ExpiryPolicy设置。

springboot2.x整合redis做缓存案例_第1张图片

spring Cache注解详解

(1)@CacheConfig:用于配置该类中会用到的一些共用的缓存配置
(2)@Cacheable:用于方法返回值加入缓存。同时在查询时,会先从缓存中取,若不存在才再发起对数据库的访问。
(3)@CachePut:配置于方法上,能够根据参数定义条件进行缓存,与@Cacheable不同的是,每次回真实调用函数,所以主要用于数据新增和修改操作上。
(4)@CacheEvict:配置于函数上,通常用在删除方法上,用来从缓存中移除对应数据
(5)@Caching:配置于函数上,组合多个Cache注解使用。

测试

1.查询1号员工
结果:第一次查询是直接查数据库,第二次查缓存
springboot2.x整合redis做缓存案例_第2张图片
springboot2.x整合redis做缓存案例_第3张图片

springboot2.x整合redis做缓存案例_第4张图片

小结

以上就是全部内容,各位大佬有什么指点的地方欢迎留言。

你可能感兴趣的:(web开发)