zoukankan      html  css  js  c++  java
  • SpringBootのRedis

     

     

     

     

     

    什么是Redis?http://www.redis.cn/

    Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。

     

    docker中安装redis

    docker pull redis

     

    运行redis

    docker run  -d -p 6379:6379 --name myredis redis 

    redis的端口号为6379,

    如果之前启动过redis,可以通过docker start id进行启动

     

     

    在springbot中如何应用Redis

    1.引入依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

    2.yml配置redis访问路径

    spring:
      datasource:
        # 配置监控服务器
        type: com.alibaba.druid.pool.DruidDataSource
        druid:
          #   druid 数据源其他配置 当添加了如下配置,我们需要在程序中增加configuration配置来将这些配置映射到系统默认配置参数上去。
          driver-class-name: com.mysql.cj.jdbc.Driver
          username: root
          password: root
          url: jdbc:mysql://192.168.100.158:3306/spring_cache?characterEncoding=utf-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useSSL=false
          initialSize: 5
          minIdle: 5
          maxActive: 20
          maxWait: 60000
          timeBetweenEvictionRunsMillis: 60000
          minEvictableIdleTimeMillis: 300000
          validationQuery: SELECT 1 FROM DUAL
          testWhileIdle: true
          testOnBorrow: false
          testOnReturn: false
          poolPreparedStatements: true
          #   配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
          filter:
            config:
              enabled: true
            stat:
              enabled: true
              db-type: mysql
            wall:
              enabled: true
              db-type: mysql
          maxPoolPreparedStatementPerConnectionSize: 20
          useGlobalDataSourceStat: true
          connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
          stat-view-servlet:
            login-username: admin
            login-password: admin
            reset-enable: false
            url-pattern: /druid/*
          web-stat-filter:
            url-pattern: /*
            exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
      redis:
        host: 192.168.100.158
    mybatis:
      configuration:
        # 开启驼峰命名法
        map-underscore-to-camel-case: true
    logging:
      level:
        # 设置包下日志输出级别
       com.seegot.mapper: debug
    debug: true

    3.创建数据库spring_cache

    /*
    Navicat MySQL Data Transfer
    ​
    Source Server         : vm
    Source Server Version : 50729
    Source Host           : 192.168.100.158:3306
    Source Database       : spring_cache
    ​
    Target Server Type    : MYSQL
    Target Server Version : 50729
    File Encoding         : 65001
    ​
    Date: 2020-05-18 13:48:39
    */SET FOREIGN_KEY_CHECKS=0;
    ​
    -- ----------------------------
    -- Table structure for department
    -- ----------------------------
    DROP TABLE IF EXISTS `department`;
    CREATE TABLE `department` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `departmentName` varchar(255) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
    ​
    -- ----------------------------
    -- Records of department
    -- ----------------------------
    INSERT INTO `department` VALUES ('1', '研发部');
    INSERT INTO `department` VALUES ('2', '测试部');
    INSERT INTO `department` VALUES ('3', '财务部');
    ​
    -- ----------------------------
    -- Table structure for employee
    -- ----------------------------
    DROP TABLE IF EXISTS `employee`;
    CREATE TABLE `employee` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `lastName` varchar(255) DEFAULT NULL,
      `email` varchar(255) DEFAULT NULL,
      `gender` int(2) DEFAULT NULL,
      `d_id` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
    ​
    -- ----------------------------
    -- Records of employee
    -- ----------------------------
    INSERT INTO `employee` VALUES ('1', 'Tom', '1', '0', '1');
    INSERT INTO `employee` VALUES ('2', 'Jerry', 'Jerry@seegot.com', '2', '2');
    ​

    4.创建bean

    Department部门 和 Employee员工

    package com.seegot.bean;
    ​
    import lombok.Data;
    ​
    /**
     * @program: spring-boot-01-cache
     * @description:
     * @author: PP Zhang
     * @create: 2020-04-27 10:46
     */
    @Data
    public class Department {
        private Integer id;
        private String departmentName;
    }
    package com.seegot.bean;
    ​
    import lombok.Data;
    ​
    import java.io.Serializable;
    ​
    /**
     * @program: spring-boot-01-cache
     * @description:
     * @author: PP Zhang
     * @create: 2020-04-27 10:47
     */
    @Data
    public class Employee  {
        private Integer id;
        private String lastName;
        private String email;
        private Integer gender;
        private Integer dId;
    }

    5.创建mapper

    package com.seegot.mapper;
    ​
    import com.seegot.bean.Department;
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Select;
    ​
    /**
     * @program: spring-boot-01-cache
     * @description:
     * @author: PP Zhang
     * @create: 2020-04-27 11:06
     */
    @Mapper
    public interface DepartmentMapper {
        @Select("select * from department where id = #{id}")
        Department getDeptById(Integer id);
    }
    package com.seegot.mapper;
    ​
    import com.seegot.bean.Employee;
    import org.apache.ibatis.annotations.*;
    ​
    /**
     * @program: spring-boot-01-cache
     * @description:
     * @author: PP Zhang
     * @create: 2020-04-27 11:06
     */
    @Mapper
    public interface EmployeeMapper {
        @Select("select * from employee where id=#{id}")
        public Employee getEmpById(Integer id);
        @Update("update employee set lastName=#{lastName},email=#{email},gender=#{gender},d_id=#{dId} where id=#{id}")
        public void updateEmp(Employee emp);
        @Delete("delete from employee where id=#{id}")
        public void deleteEmpById(Integer id);
        @Insert("insert into employee(lastName,email,gender,d_id) values (#{lastName}),#{email},#{gender},#{dId}")
        public  void insertEmp(Employee emp);
        @Select("select * from employee where lastName = #{name}")
        public Employee getEmpName(String name);
    }

    6.创建service

    package com.seegot.service;
    ​
    import com.seegot.bean.Department;
    import com.seegot.mapper.DepartmentMapper;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cache.annotation.Cacheable;
    import org.springframework.stereotype.Service;
    ​
    /**
     * @program: spring-boot-01-cache
     * @description:
     * @author: PP Zhang
     * @create: 2020-05-18 10:37
     */
    @Service
    public class DeptService {
        @Autowired
        DepartmentMapper departmentMapper;
        @Cacheable(cacheNames = "dept")
        public Department getDeptById(Integer id){
            System.out.println("查询部门:"+id);
            Department dept =  departmentMapper.getDeptById(id);
            return  dept;
        }
    }
    package com.seegot.service;
    ​
    import com.seegot.bean.Employee;
    import com.seegot.mapper.EmployeeMapper;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cache.annotation.*;
    import org.springframework.stereotype.Service;
    ​
    /**
     * @program: spring-boot-01-cache
     * @description:
     * @author: PP Zhang
     * @create: 2020-04-27 11:15
     */
    @CacheConfig(cacheNames = "emp") // 抽取公共的缓存部分,
    @Service
    public class EmployeeService {
        @Autowired
        EmployeeMapper employeeMapper;
        /**
        * @Description:
         *      将方法运行的结果进行缓存,以后再要相同的数据,直接从缓存中获取,不用调用方法去数据库查询。
         *  CacheManager管理多个Cache组件的,对缓存真正的CRUD操作在Cache组件中,每个缓存组件有自己唯一的名字;
         * @Cacheable几个属性:(key-value)
         *      cacheNames/values:指定缓存组件的名字。讲方法的反馈结果放在哪个缓存中,而且可以使数组的方式,可以指定多个缓存
         *      key:缓存数据时用的key;可以用它来指定,如果不指定Key默认是使用方法参数的值;
         *          编写SpEL:
         *              #id 是参数id的值。
         *      keyGenerator:key的生成器,可以自定义key的生成器组件id
         *      指定了Key 就不要再指定keyGenerator 二选一
         *      cacheManager:指定缓存管理器;或者cacheResolver指定获取解析器
         *      condition:指定符合条件的情况下才会缓存。@Cacheable(cacheNames = "emp",condition = "#id>0")
         *      unless:否定缓存,当unless指定的条件为true,方法返回值就不被缓存。可以获取到结果进行判断。unless = "#result==null
         *      sync:是否开启异步模式
         *
         *  原理:
         *      1.自动配置类:CacheAutoConfiguration
         *      2.缓存配置类
         *
         *      3.哪些配置类生效?
         *          SimpleCacheConfiguration
         *
         *   运行流程:
         * @Cacheable
         *      1.方法运行之前,先去查询Cache(缓存组件),按照cacheNames指定的名字获取;
         *      (CacheManager先获取相应的缓存),第一次获取缓存,如果没有Cache组件会自动创建,
         *      2.去Cache中查找缓存的内容,按使用一个Key,默认就是方法的参数;
         *        key是按照某种策略生成的。默认是使用keyGenerator生成的,默认使用SimpleKeyGenerator生成。
         *        SimpleKeyGenerator生成Key的默认策略:
         *          如果没有参数;key=new SimpleKey();
         *          如果有一个参数:key=参数的值()
         *          如果有多个参数:key=new SimpleKey(params);
         *      3.没有查到缓存就调用目标方法;
         *      4.将目标方法返回的结果,放进缓存中
         *
         *       @Cacheable标注的方法执行之前下来检查缓存中有没有这个数据,默认按照参数的值作为key去查询缓存,
         *       如果没有就运行方法并将结果放到缓存;以后在来调用,就可以直接使用缓存中的数据;
         *
         *
         *       核心:
         *          1)使用CacheManager【ConcurrentMapCacheManager】按照名字得到Cache【ConcurrentMapCache】组件
         *          2)key使用keyGenerator生成的,默认是SimpleKeyGenerator生成的。
        * @Param:
        * @return:
        * @Author: PP Zhang
        * @Date: 2020/4/27
        */
        // @Cacheable(value="emp",keyGenerator=myKeyGenerator)
        //  @Cacheable(cacheNames = "emp",key = "#root.methodName+'['+#id+']'",condition = "#a0>1 and #root.nethodName eq['aaa']")
        //   @Cacheable(cacheNames = "emp",key = "#id") 当不在类上进行@CacheConfig()的时候,用它
        @Cacheable(/*cacheNames = "emp",*/key = "#id")
        public Employee getEmp(Integer id){
            System.out.println("查询"+id+"号的员工信息");
            Employee employee = employeeMapper.getEmpById(id);
            return  employee;
        }
        /**
         * @CachePut:即调用方法,又更新缓存数据;
         * 修改了数据库的某个数据,同时更新缓存;
         * 运行时机:
         *  1.先调用目标方法
         *  2.将目标方法结果缓存起来
         *
         * 测试步骤:
         *  1.查询1号员工;查到的结果会放到缓存中。
         *  key:1  value:lastName:Lilei
         *  2.以后查询还是之前的结果。
         *  3.更新1号员工信息。【lastName:zhangsan;gender=1】
         *      使用 @CachePut(value = "emp") 其实也将该条结果存入了缓存,
         *      由于没有指定缓存名称,所以默认是参数也就是 employee
         *      key:employee  value:返回的employee对象。
         *      @Cacheable是不可能用#result的。
         *  4.查询1号员工
         *     应该是更新的员工
         *     key = "#employee.id" 使用传入的参数员工id;
         *     key="#result.id" 是返回后的Id
         *
         *     为什么是没有更新前的?
         * */
        @CachePut(/*value = "emp",*/key = "#result.id")
        public  Employee updateEmp(Employee employee){
            System.out.println("updateEmp"+employee);
            employeeMapper.updateEmp(employee);
            return  employee;
        }
        /**
         * @CacheEvict:清除缓存
         * key 指定要清除的Key
         *
         * allEntries = true 删除指定缓存中的所有数据
         *
         * beforeInvocation = false 缓存的清除是否在方法之前执行?
         *  默认缓存清除是在方法执行之后执行的,如果方法出现异常,缓存就不会被清除。
         *
         *  beforeInvocation = true
         *   代表清除缓存操作是在方法运行之前执行的,无论方法是否出现异常,缓存都被清除。
         * */
        @CacheEvict(/*value = "emp",*//*key = "#id",*//*allEntries = true*/beforeInvocation = true)
        public  void deleteEmp(Integer id){
            System.out.println("deleteEmp"+id);
            // employeeMapper.deleteEmpById(id);
            int i = 10/0;
        }
    ​
        // 定义复杂的注解
        @Caching(
                cacheable = {
                        @Cacheable(/*value="emp",*/key = "#name")
                },
                put = {
                        @CachePut(/*value="emp",*/key = "#result.id"),
                        @CachePut(/*value = "emp",*/key = "#result.email")
                }
        )
        public  Employee getEmpByName(String name){
            Employee employee = employeeMapper.getEmpName(name);
            return  employee;
        }
    }

    7.创建config

    package com.seegot.config;
    ​
    import com.fasterxml.jackson.annotation.JsonAutoDetect;
    import com.fasterxml.jackson.annotation.PropertyAccessor;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
    import org.springframework.cache.CacheManager;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.cache.RedisCacheConfiguration;
    import org.springframework.data.redis.cache.RedisCacheManager;
    import org.springframework.data.redis.cache.RedisCacheWriter;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
    import org.springframework.data.redis.serializer.RedisSerializationContext;
    import org.springframework.data.redis.serializer.RedisSerializer;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    ​
    /**
     * @program: spring-boot-01-cache
     * @description:
     * @author: PP Zhang
     * @create: 2020-05-15 13:56
     */
    @Configuration
    public class MyRedisConfig { 
    ​
        @Bean
        public RedisTemplate<String,Object>redisTemplate(RedisConnectionFactory redisConnectionFactory){
            RedisTemplate<String,Object>template = new RedisTemplate<>();
            template.setConnectionFactory(redisConnectionFactory);
            template.setKeySerializer(new StringRedisSerializer());
            template.setValueSerializer(valueSerializer());
            template.setHashKeySerializer(new StringRedisSerializer());
            template.setHashValueSerializer(valueSerializer());
            return  template;
        }
        @Bean
        public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory){
            RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
            RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                    .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()));
            redisCacheConfiguration.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
            return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
        }
        private RedisSerializer<Object> valueSerializer() {
            Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            // objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
            //因为上面那句代码已经被标记成作废,因此用下面这个方法代替,仅仅测试了一下,不知道是否完全正确
            objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL);
            serializer.setObjectMapper(objectMapper);
            return serializer;
        }
    }
     
  • 相关阅读:
    Running OOM killer script for process 32248 for Solr on port 8983
    List删除元素
    Oracle联合主键
    synchronized的四种用法
    数据库 乐观锁与悲观锁
    noip2011普及组 统计单词数
    bzoj3751 noip2014解方程
    汕头市队赛SRM07
    noip2010 导弹拦截&&vijos1810
    noip2009普及组 细胞分裂&&vijos1814
  • 原文地址:https://www.cnblogs.com/pengpengzhang/p/12910180.html
Copyright © 2011-2022 走看看