SpringBoot--中间件技术-2:整合redis,redis实战小案例,springboot cache,cache简化redis的实现,含代码

SpringBoot整合Redis

实现步骤

  1. 导pom文件坐标

    <!--redis依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    
  2. yaml主配置文件,配置redis端口号

    spring:
      redis:
        host: localhost
        port: 6379
    
  3. 测试类

    字符串专用类:StringRedisTemplate stringRedisTemplate

    @Autowired
    public RedisTemplate redisTemplate;
    @Test
    public void stringTest(){
        // 各种类型支持
        stringRedisTemplate.opsForValue();
        stringRedisTemplate.opsForList();
        stringRedisTemplate.opsForSet();
        stringRedisTemplate.opsForHash();
        stringRedisTemplate.opsForZSet();
    
        // 字符串
        stringRedisTemplate.opsForValue().set("teacher","刘老板");
        String teacher = stringRedisTemplate.opsForValue().get("teacher");
        System.out.println("stringRedisTemplate输出结果"+teacher);
    
        // 操作list列表
        stringRedisTemplate.opsForList().leftPush("tang","李白");
        stringRedisTemplate.opsForList().leftPush("tang","杜甫");
    
        stringRedisTemplate.opsForList().leftPushAll("songAll","欧阳修","苏轼","苏辙");
        List<String> songAll = stringRedisTemplate.opsForList().range("songAll", 0, 2);
        songAll.forEach(System.out::println);
    
    }
    

    对象专用类:RedisTemplate redisTemplate

    @Autowired(required = false)
    public RedisTemplate redisTemplate;
    @Test
    public void redisTemplate(){
        // 各种类型支持
        redisTemplate.opsForValue();
        redisTemplate.opsForList();
        redisTemplate.opsForSet();
        redisTemplate.opsForHash();
        redisTemplate.opsForZSet();
    
        ValueOperations valueOperations = redisTemplate.opsForValue();
        valueOperations.set("panda","花花");
        String panda = (String) valueOperations.get("panda");
        System.out.println(panda);
    
        Student student = new Student(1,"惠晨怡","女");
        redisTemplate.opsForValue().set("stu",student);
        Student student1 = (Student) redisTemplate.opsForValue().get("stu");
        System.out.println(student1);
    
        redisTemplate.opsForList().leftPushAll("animal","狗","猫","龙","鼠");
        List animal = redisTemplate.opsForList().range("animal", 0, 3);
        animal.forEach(System.out::println);
    
    }
    

    在可视化页面中查看对象存入的键和值,看不明白,没有可读性,可以使用自定义类

    自定义类实现步骤:

    pom文件导入fastJson

    <!--fastjson工具包 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.3</version>
    </dependency>
    
    <dependency>
        <groupId>com.colobu</groupId>
        <artifactId>fastjson-jaxrs-json-provider</artifactId>
        <version>0.3.1</version>
    </dependency>
    

    添加配置类RedisConfig

    @Configuration
    public class RedisConfig {
    
        @Bean
        public RedisTemplate<Object,Object> jsonRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
            // 创建自定义模板
            RedisTemplate<Object, Object> template = new RedisTemplate<>();
            //配置json类型的序列化工具
            template.setKeySerializer(new StringRedisSerializer());
            template.setDefaultSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));
    template.setConnectionFactory(redisConnectionFactory);
            return template;
        }
    }
    

    测试:装配的redis模板类需要和自定义的同名

    @Autowired
    public RedisTemplate jsonRedisTemplate;
    @Test
    public void test03(){
        jsonRedisTemplate.opsForValue();
        jsonRedisTemplate.opsForList();
        jsonRedisTemplate.opsForSet();
        jsonRedisTemplate.opsForHash();
        jsonRedisTemplate.opsForZSet();
    
        Student student1 = new Student(2,"惠晨怡","男");
        Student student2 = new Student(3,"尚恒通","男");
        Student student3 = new Student(4,"李竟坡","男");
    
        ArrayList<Student> students = new ArrayList<>(Arrays.asList(student1,student2,student3));
    
        jsonRedisTemplate.opsForValue().set("stus",students);
        Object stus = jsonRedisTemplate.opsForValue().get("stus");
        String s = JSON.toJSONString(stus);
        List<Student> list = JSONObject.parseArray(s, Student.class);
        list.forEach(System.out::println);
    }
    

SpringBoot整合Redis实战案例

redis在项目中起到缓存作用,案例演示redis在项目中的实现

  1. 导入pom.xml文件

    springboot版本2.7.14

    <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>
    
    <!--mysql-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.29</version>
    </dependency>
    
    <!--mybatis-->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.0.1</version>
    </dependency>
    
    <!--redis-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    
  2. yaml配置文件配置数据源和redis

    # 配置数据源
    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/spring?serverTimezone=GMT
        username: root
        password: 123456
    
      # 配置redis
      redis:
        host: localhost
        port: 6379
    
    mybatis:
      configuration:
        map-underscore-to-camel-case: true
    

    用到了mybatis,所以配置了一个自动驼峰映射

  3. Redis自定义模板配置类

    @Component
    public class RedisConfig {
    
        @Bean
        public RedisTemplate<Object,Object> jsonRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
            RedisTemplate<Object, Object> template = new RedisTemplate<>();
            template.setKeySerializer(new StringRedisSerializer());
            template.setDefaultSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));
            template.setConnectionFactory(redisConnectionFactory);
            return template;
        }
    }
    
  4. 导入redisUtil工具类,工具栏中封装了大量redis操作代码,一般真实开发环境中都可以看到一个公司自己封装的RedisUtil

    @Component
    public  class RedisUtil {
    
        @Autowired(required = false)
        private RedisTemplate jsonRedisTemplate;
    
        // =========================================================
        /**
         * 指定缓存失效时间
         * @param key  键
         * @param time 时间(秒)
         */
        public boolean expire(String key, long time) {
            try {
                if (time > 0) {
                    jsonRedisTemplate.expire(key, time, TimeUnit.SECONDS);
                }
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    
        /**
         * 根据key 获取过期时间
         * @param key 键 不能为null
         * @return 时间(秒) 返回0代表为永久有效
         */
        public long getExpire(String key) {
            return jsonRedisTemplate.getExpire(key, TimeUnit.SECONDS);
        }
    
    
        /**
         * 判断key是否存在
         * @param key 键
         * @return true 存在 false不存在
         */
        public boolean hasKey(String key) {
            try {
                return jsonRedisTemplate.hasKey(key);
            } catch (Exception e) {
                return false;
            }
        }
    
    
        /**
         * 删除缓存
         * @param key 可以传一个值 或多个
         */
        @SuppressWarnings("unchecked")
        public void del(String... key) {
            if (key != null && key.length > 0) {
                if (key.length == 1) {
                    jsonRedisTemplate.delete(key[0]);
                } else {
                    jsonRedisTemplate.delete(CollectionUtils.arrayToList(key));
                }
            }
        }
    
    
        // ============================String=============================
    
        /**
         * 普通缓存获取
         * @param key 键
         * @return 值
         */
        public Object get(String key) {
            return key == null ? null : jsonRedisTemplate.opsForValue().get(key);
        }
    
        /**
         * 普通缓存放入
         * @param key   键
         * @param value 值
         * @return true成功 false失败
         */
    
        public boolean set(String key, Object value) {
            try {
                jsonRedisTemplate.opsForValue().set(key, value);
                return true;
            } catch (Exception e) {
                return false;
            }
        }
    
    
        /**
         * 普通缓存放入并设置时间
         * @param key   键
         * @param value 值
         * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
         * @return true成功 false 失败
         */
    
        public boolean set(String key, Object value, long time) {
            try {
                if (time > 0) {
                    jsonRedisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
                } else {
                    set(key, value);
                }
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    
    
        /**
         * 递增
         * @param key   键
         * @param delta 要增加几(大于0)
         */
        public long incr(String key, long delta) {
            if (delta < 0) {
                throw new RuntimeException("递增因子必须大于0");
            }
            return jsonRedisTemplate.opsForValue().increment(key, delta);
        }
    
    
        /**
         * 递减
         * @param key   键
         * @param delta 要减少几(小于0)
         */
        public long decr(String key, long delta) {
            if (delta < 0) {
                throw new RuntimeException("递减因子必须大于0");
            }
            return jsonRedisTemplate.opsForValue().increment(key, -delta);
        }
    
    
        // ================================Map=================================
    
        /**
         * HashGet
         * @param key  键 不能为null
         * @param item 项 不能为null
         */
        public Object hget(String key, String item) {
            return jsonRedisTemplate.opsForHash().get(key, item);
        }
    
        /**
         * 获取hashKey对应的所有键值
         * @param key 键
         * @return 对应的多个键值
         */
        public Map<Object, Object> hmget(String key) {
            return jsonRedisTemplate.opsForHash().entries(key);
        }
    
        /**
         * HashSet
         * @param key 键
         * @param map 对应多个键值
         */
        public boolean hmset(String key, Map<String, Object> map) {
            try {
                jsonRedisTemplate.opsForHash().putAll(key, map);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    
    
        /**
         * HashSet 并设置时间
         * @param key  键
         * @param map  对应多个键值
         * @param time 时间(秒)
         * @return true成功 false失败
         */
        public boolean hmset(String key, Map<String, Object> map, long time) {
            try {
                jsonRedisTemplate.opsForHash().putAll(key, map);
                if (time > 0) {
                    expire(key, time);
                }
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    
    
        /**
         * 向一张hash表中放入数据,如果不存在将创建
         *
         * @param key   键
         * @param item  项
         * @param value 值
         * @return true 成功 false失败
         */
        public boolean hset(String key, String item, Object value) {
            try {
                jsonRedisTemplate.opsForHash().put(key, item, value);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    
        /**
         * 向一张hash表中放入数据,如果不存在将创建
         *
         * @param key   键
         * @param item  项
         * @param value 值
         * @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
         * @return true 成功 false失败
         */
        public boolean hset(String key, String item, Object value, long time) {
            try {
                jsonRedisTemplate.opsForHash().put(key, item, value);
                if (time > 0) {
                    expire(key, time);
                }
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    
    
        /**
         * 删除hash表中的值
         *
         * @param key  键 不能为null
         * @param item 项 可以使多个 不能为null
         */
        public void hdel(String key, Object... item) {
            jsonRedisTemplate.opsForHash().delete(key, item);
        }
    
    
        /**
         * 判断hash表中是否有该项的值
         *
         * @param key  键 不能为null
         * @param item 项 不能为null
         * @return true 存在 false不存在
         */
        public boolean hHasKey(String key, String item) {
            return jsonRedisTemplate.opsForHash().hasKey(key, item);
        }
    
    
        /**
         * hash递增 如果不存在,就会创建一个 并把新增后的值返回
         *
         * @param key  键
         * @param item 项
         * @param by   要增加几(大于0)
         */
        public double hincr(String key, String item, double by) {
            return jsonRedisTemplate.opsForHash().increment(key, item, by);
        }
    
    
        /**
         * hash递减
         *
         * @param key  键
         * @param item 项
         * @param by   要减少记(小于0)
         */
        public double hdecr(String key, String item, double by) {
            return jsonRedisTemplate.opsForHash().increment(key, item, -by);
        }
    
    
        // ============================set=============================
    
        /**
         * 根据key获取Set中的所有值
         * @param key 键
         */
        public Set<Object> sGet(String key) {
            try {
                return jsonRedisTemplate.opsForSet().members(key);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    
    
        /**
         * 根据value从一个set中查询,是否存在
         *
         * @param key   键
         * @param value 值
         * @return true 存在 false不存在
         */
        public boolean sHasKey(String key, Object value) {
            try {
                return jsonRedisTemplate.opsForSet().isMember(key, value);
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    
    
        /**
         * 将数据放入set缓存
         *
         * @param key    键
         * @param values 值 可以是多个
         * @return 成功个数
         */
        public long sSet(String key, Object... values) {
            try {
                return jsonRedisTemplate.opsForSet().add(key, values);
            } catch (Exception e) {
                e.printStackTrace();
                return 0;
            }
        }
    
    
        /**
         * 将set数据放入缓存
         *
         * @param key    键
         * @param time   时间(秒)
         * @param values 值 可以是多个
         * @return 成功个数
         */
        public long sSetAndTime(String key, long time, Object... values) {
            try {
                Long count = jsonRedisTemplate.opsForSet().add(key, values);
                if (time > 0)
                    expire(key, time);
                return count;
            } catch (Exception e) {
                e.printStackTrace();
                return 0;
            }
        }
    
    
        /**
         * 获取set缓存的长度
         *
         * @param key 键
         */
        public long sGetSetSize(String key) {
            try {
                return jsonRedisTemplate.opsForSet().size(key);
            } catch (Exception e) {
                e.printStackTrace();
                return 0;
            }
        }
    
    
        /**
         * 移除值为value的
         *
         * @param key    键
         * @param values 值 可以是多个
         * @return 移除的个数
         */
    
        public long setRemove(String key, Object... values) {
            try {
                Long count = jsonRedisTemplate.opsForSet().remove(key, values);
                return count;
            } catch (Exception e) {
                e.printStackTrace();
                return 0;
            }
        }
    
        // ===============================list=================================
    
        /**
         * 获取list缓存的内容
         *
         * @param key   键
         * @param start 开始
         * @param end   结束 0 到 -1代表所有值
         */
        public List<Object> lGet(String key, long start, long end) {
            try {
                return jsonRedisTemplate.opsForList().range(key, start, end);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    
    
        /**
         * 获取list缓存的长度
         *
         * @param key 键
         */
        public long lGetListSize(String key) {
            try {
                return jsonRedisTemplate.opsForList().size(key);
            } catch (Exception e) {
                e.printStackTrace();
                return 0;
            }
        }
    
    
        /**
         * 通过索引 获取list中的值
         *
         * @param key   键
         * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
         */
        public Object lGetIndex(String key, long index) {
            try {
                return jsonRedisTemplate.opsForList().index(key, index);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    
    
        /**
         * 将list放入缓存
         *
         * @param key   键
         * @param value 值
         */
        public boolean lSet(String key, Object value) {
            try {
                jsonRedisTemplate.opsForList().rightPush(key, value);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    
    
        /**
         * 将list放入缓存
         * @param key   键
         * @param value 值
         * @param time  时间(秒)
         */
        public boolean lSet(String key, Object value, long time) {
            try {
                jsonRedisTemplate.opsForList().rightPush(key, value);
                if (time > 0)
                    expire(key, time);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
    
        }
    
    
        /**
         * 将list放入缓存
         *
         * @param key   键
         * @param value 值
         * @return
         */
        public boolean lSet(String key, List<Object> value) {
            try {
                jsonRedisTemplate.opsForList().rightPushAll(key, value);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
    
        }
    
    
        /**
         * 将list放入缓存
         *
         * @param key   键
         * @param value 值
         * @param time  时间(秒)
         * @return
         */
        public boolean lSet(String key, List<Object> value, long time) {
            try {
                jsonRedisTemplate.opsForList().rightPushAll(key, value);
                if (time > 0)
                    expire(key, time);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    
        /**
         * 根据索引修改list中的某条数据
         *
         * @param key   键
         * @param index 索引
         * @param value 值
         * @return
         */
    
        public boolean lUpdateIndex(String key, long index, Object value) {
            try {
                jsonRedisTemplate.opsForList().set(key, index, value);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    
        /**
         * 移除N个值为value
         *
         * @param key   键
         * @param count 移除多少个
         * @param value 值
         * @return 移除的个数
         */
    
        public long lRemove(String key, long count, Object value) {
            try {
                Long remove = jsonRedisTemplate.opsForList().remove(key, count, value);
                return remove;
            } catch (Exception e) {
                e.printStackTrace();
                return 0;
            }
    
        }
    
    }
    
  5. 实体类POJO

    public class Student {
        private int stuId;
        private String stuName;
        private String stuSex;
        // get,set,构造,toString等
    }
    
  6. Dao层:Mapper

    @Mapper
    public interface StudentMapper {
        @Delete("delete from student where stu_id = #{id}")
        public int delete(Integer id);
    
        @Select("select * from student where stu_id = #{id}")
        public Student find(Integer id);
    }
    
  7. 业务层:

    接口

    public interface IStudentService {
    
        public void delete(int id);
    
        public Student find(int id);
        
    }
    

    实现类

    @Service
    public class StudentServiceImp implements IStudentService {
    
        @Autowired(required = false)
        private StudentMapper mapper;
    
        @Autowired
        private RedisUtil redisUtil;
    
        // 删除用户策略:删除数据表中数据,然后删除缓存
        @Override
        public void delete(int id) {
            // 删除数据库
            int res = mapper.delete(id);
            String key = "student:id:"+id;
            // 判断数据库是否删除成功
            if(res != 0){
                boolean hasKey = redisUtil.hasKey(key);
                if(hasKey){
                    redisUtil.del(key);
                    System.out.println("删除了缓存中的key:" + key);
                }
            }
        }
    
        // 获取用户策略:先从缓存中获取用户,没有则取数据表中数据,再将数据写入缓存
        @Override
        public Student find(int id) {
            String key = "student:id:" + id;
    
            //1.1判断key在redis中是否存在
            boolean hasKey = redisUtil.hasKey(key);
            if (hasKey) {
                //1.2存在缓存则直接获取
                Object stu = redisUtil.get(key);
                ObjectMapper change = new ObjectMapper();
                Student student =   change.convertValue(stu,Student.class);
                System.out.println("==========从缓存中获得数据=========");
                System.out.println(student.getStuName());
                System.out.println("==============================");
                return student;
            } else {
                //1.3不存在缓存,先从数据库中获取,在保存至redis,最后返回用户
                Student student = mapper.find(id);
                System.out.println("==========从数据表中获得数据=========");
                System.out.println(student.getStuName());
                System.out.println("==============================");
                if (student != null){
                    redisUtil.set(key, student);//写入缓存
                }
                return student;
            }
        }
    }
    
  8. 控制器

    @RestController
    public class StudentController {
    
        @Autowired
        IStudentService service;
    
        @RequestMapping("/delete/{id}")
        public Integer delete(@PathVariable("id") int id){
            service.delete(id);
            return id;
        }
    
        @RequestMapping("/find/{id}")
        public Student find(@PathVariable("id") int id){
            Student student = service.find(id);
            return student;
        }
    
    
    }
    
  9. 启动服务,地址栏中测试查看控制台打印结果,(测试时一定要保证redis服务正在运行,否则存不进redis

    第一次访问localhost:8080/find/1显示从数据表中获得的数据,第二次访问显示缓存中获取的数据

    在这里插入图片描述

SpringBoot Cache

SpringBoot Cache介绍

Spring Cache是一个框架, 实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能

Spring Cache提供了一层抽象,底层可以切换不同的cache实现。具体就是通过CacheManager接口来统一不同的缓存技术。

CacheManager缓存管理器是Spring提供的各种缓存技术抽象接口

针对不同的缓存技术需要实现不同的CacheManager:

CacheManager描述
EhCacheCacheManager使用EhCache作为缓存技术(Spring Cache框架操作的默认缓存)
GuavaCacheManager使用Google的GuavaCache作为缓存技术
RedisCacheManager使用Redis作为缓存技术

SpringBoot Cache常用注解

注解说明
@EnableCaching开启缓存注解功能
@Cacheable在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,调用方法并将方法返回值放到缓存中
@CachePut将方法的返回值放到缓存中
@CacheEvict将一条或多条数据从缓存中删除

使用步骤:

  1. 引入缓存启动器:spring-boot-starter-cache,spring-boot-starter-data-redis

  2. @EnableCaching:在启动类上,开启基于注解的缓存

  3. @Cacheable : 标在方法上,返回的结果会进行缓存

属性: value/cacheNames缓存的名字

​ key : 作为缓存中的Key值,可自已使用 SpEL表达式指定(不指定就是参数值), 缓存结果是

​ 方法返回值

名字描述示例
methodName当前被调用的方法名#root.methodName
target当前被调用的目标对象#root.target
targetClass当前被调用的目标对象类#root.targetClass
args当前被调用的方法的参数列表#root.args[0]
caches当前方法调用使用的缓存列表(如@Cacheable(value={“cache1”,“cache2”})),则有两个cache#root.caches[0].name
argument name方法参数的名字. 可以直接 #参数名 ,也可以使用 #p0或#a0 的形式,0代表参数的索引;#iban 、 #a0 、 #p0
result方法执行后的返回值(仅当方法执行之后的判断有效,在@CachePut 使用于更新数据后可用)#result

SpringBoot Cache案例简化Redis

代码实现演示:

  1. pom文件导坐标

    <!--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-cache</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.0.1</version>
    </dependency>
    
    <dependency>
       <groupId>mysql</groupId>
       <artifactId>mysql-connector-java</artifactId>
       <scope>runtime</scope>
    </dependency>
    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-test</artifactId>
       <scope>test</scope>
    </dependency>
    
  2. yaml或properties主配置文件

    spring.datasource.username=root
    spring.datasource.password=123456
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/spring?serverTimezone=GMT%2B8
    
    #开启日志管理,可以查看sql语句
    logging.level.com.apesource.springboot_redis03.mapper=debug
    debug=true
    
    #配置要连接redis的地址
    spring.redis.host=localhost
    spring.redis.port=6379
    
  3. POJO实体类

    根据要操作的表写,演示为student

    public class Student implements Serializable{
    
        private Integer stuId;
    
        private String stuName;
    
        private String stuSex;
    
        // get、set、toString、有参、无参构造
    }
    
  4. Dao层StudentMapper

    public interface StudentMapper {
    
        @Select("select * from Student where stu_id = #{id}")
        public Student getStudentById(Integer id);
    
    
        @Delete("delete from student where stu_id = #{id}")
        public int deleteStudentById(Integer id);
    
        @Update("update student  set stu_name=#{stuName},stu_sex=#{stuSex} where stu_id = #{stuId}")
        public int updateById(Student student);
    
    }
    
  5. Service层

    演示Cache简化redis实现,业务直接写实现类,没写接口

    @Service
    public class StudentService {
    
    
        @Autowired(required = false)
        StudentMapper mapper;
    
    
    
        //根据@Cacheable注解中的cacheNames+key拼接后的值为key
        @Cacheable(cacheNames = "students",key = "#id")
        public Student findById(Integer id){
            return mapper.getStudentById(id);
        }
    
    
        @CacheEvict(cacheNames = "students",key = "#id")
        public void deleteStudentById(Integer id){
            mapper.deleteStudentById(id);
        }
    
        @CachePut(cacheNames = "students",key = "#result.stuId")
        public Student updateById(Student student){
            mapper.updateById(student);
            return student;
        }
    
    }
    

    在业务层的方法中,加SpringBoot Cache的注解:

    cacheNames会在缓存中开辟一块儿叫"students"的空间,以键值对的形式存放数据,键是cacheNames+key拼接组成,value就是被标注注解的方法返回值

  6. 控制器StudentController

    @RestController
    public class UserController {
    
        @Autowired
        StudentService userService;
    
        @GetMapping("/findById/{id}")
        public Student findById(@PathVariable("id") Integer id) {
            Student stu = userService.findById(id);
            return stu;
        }
    
    
    
        @GetMapping("/delete/{id}")
        public Integer delete(@PathVariable("id") Integer id) {
            userService.deleteStudentById(id);
            return id;
        }
    
        @GetMapping("/update/{id}/{name}/{hobby}")
        public Integer update(@PathVariable Integer id,@PathVariable String name,@PathVariable String sex) {
            userService.updateById(new Student(id,name,sex));
            return id;
        }
    
    }	
    
  7. 启动类上添加注解

    @SpringBootApplication
    @MapperScan("com.apesource.springboot_redis03")
    @EnableCaching
    public class SpringbootRedis03Application {
    
       public static void main(String[] args) {
          SpringApplication.run(SpringbootRedis03Application.class, args);
       }
    
    }
    
  8. 启动服务,浏览器访问localhost:8080/findById/1,访问之后刷新再次访问

    注意启动程序服务之前,需要先把redis运行起来

    在这里插入图片描述

    第一次访问时,从数据库中获取的数据

    第二次访问,没有SQL语句,但是也得到了数据,证明cache实现了缓存的作用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/134355.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于python+TensorFlow+Django卷积网络算法+深度学习模型+蔬菜识别系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 介绍了TensorFlow在图像识别分类中的应用&#xff0c;并通过相关代码进行了讲解。通过TensorFlow提供的工具和库&am…

K8S知识点(八)

&#xff08;1&#xff09;实战入门-Label 通过标签实现Pod的区分&#xff0c;说白了就是一种标签选择机制 可以使用命令是否加了标签&#xff1a; 打标签&#xff1a; 更新标签&#xff1a; 筛选标签&#xff1a; 修改配置文件&#xff0c;重新创建一个pod 筛选&#xff1…

Python---split()方法 + join()方法

split()方法 split 英 /splɪt/ v. 分裂&#xff0c;使分裂&#xff08;成不同的派别&#xff09;&#xff1b;分开&#xff0c;使分开&#xff08;成为几个部份&#xff09;&#xff1b;&#xff08;使&#xff09;撕裂&#xff1b;分担&#xff0c;分享&#xff1b;划破&…

kubeadm部署k8s及高可用

目录 CNI 网络组件 1、flannel的功能 2、flannel的三种模式 3、flannel的UDP模式工作原理 4、flannel的VXLAN模式工作原理 5、Calico主要组成部分 6、calico的IPIP模式工作原理 7、calico的BGP模式工作原理 8、flannel 和 calico 的区别 Kubeadm部署k8s及高可用 1、…

如何用 GPTs 构建自己的知识分身?(进阶篇)

&#xff08;注&#xff1a;本文为小报童精选文章&#xff0c;已订阅小报童或加入知识星球「玉树芝兰」用户请勿重复付费&#xff09; 有了这些改进&#xff0c;你可以快速判断 GPT 助手给出的答案是真实还是「幻觉」了。 问题 在《如何用自然语言 5 分钟构建个人知识库应用&am…

KVM虚拟机迁移原理与实践

虚拟机迁移 迁移(migration)包括系统整体的迁移和某个工作负载的迁移&#xff0c;系统整体迁移是将系统上的所有软件&#xff0c;包括操作系统&#xff0c;完全复制到另一台物理硬件机器上&#xff0c;而工作负载迁移仅仅迁移特定的工作负载。 虚拟化技术的出现&#xff0c;丰…

Day03:注意事项、this关键字、构造器、JavaBean、String、ArrayList

OOP的注意事项 类名要跟class文件名一致&#xff08;一个class可以有多个类&#xff0c;但只有一个public&#xff0c;且与文件名一致&#xff09;&#xff0c;命名介意大驼峰&#xff1b;如果某个对象没有变量指向他&#xff0c;就成垃圾对象了&#xff08;空指针&#xff09…

Redis(三)

4、分布式锁 4.1 、基本原理和实现方式对比 分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁。 分布式锁的核心思想就是让大家都使用同一把锁,只要大家使用的是同一把锁,那么我们就能锁住线程,不让线程进行,让程序串行执行,这就是分布式锁的核心思路 那么…

FM8317-USB TYPE-C PD 多协议控制器

产品描述&#xff1a; FM8317是一款集成了USB Type-C、USB Power Delivery&#xff08;PD3.0&#xff09;、PPS的多协议端口控制器&#xff0c;为AC-DC适配器、车载充电器等设备提供高性价比的USB Type-C 端口充电解决方案。 FM8317内置的Type-C协议可以支持Type-C设备插入自动…

Netty - 回顾Netty高性能原理和框架架构解析

文章目录 概述JDK 原生 NIO 程序的问题Why Netty使用场景Related ProjectsNetty 高性能设计I/O 模型【阻塞 I/O】&#xff1a;【I/O 复用模型】【基于 Buffer】 线程模型事件驱动模型Reactor 线程模型Netty的线程模型异步处理 Netty框架的架构设计功能特性模块组件Bootstrap、S…

Linux驱动开发——PCI设备驱动

目录 一、 PCI协议简介 二、PCI和PCI-e 三、Linux PCI驱动 四、 PCI设备驱动实例 五、 总线类设备驱动开发习题 一、 PCI协议简介 PCI (Peripheral Component Interconnect&#xff0c;外设部件互联) 局部总线是由Intel 公司联合其他几家公司一起开发的一种总线标准&#…

2560 动物保护宣传网站设计JSP【程序源码+文档+调试运行】

摘要 本文介绍了一个动物保护宣传网站的系统的设计与实现。该系统包括前台用户模块和后台管理员模块&#xff0c;具有用户注册/登录、新闻、资源库、法律法规、图片赏析、留言板、关于我们、用户后台等功能。通过数据库设计和界面设计&#xff0c;实现了系统的基本功能&#x…

腾讯云3年期轻量应用服务器优惠(薅羊毛教程)

腾讯云轻量应用服务器特价是有新用户限制的&#xff0c;所以阿腾云建议大家选择3年期轻量应用服务器&#xff0c;一劳永逸&#xff0c;免去续费困扰。腾讯云轻量应用服务器3年优惠可以选择2核2G4M和2核4G5M带宽&#xff0c;3年轻量2核2G4M服务器540元&#xff0c;2核4G5M轻量应…

SW如何显示样条曲线的控标

刚刚学习隔壁老王的sw画图时&#xff0c;怎么点都点不出样条曲线的控标&#xff0c;于是果断查询了一下解决方法&#xff0c;其实很简单&#xff0c;只不过是培训机构故意不说&#xff0c;叫你还解决不了&#xff0c;难受了就会花钱买他们的课了。毕竟如果学会了怎么解决问题了…

泛微E-Office信息泄露漏洞复现

简介 Weaver E-Office是中国泛微科技&#xff08;Weaver&#xff09;公司的一个协同办公系统。 Weaver E-Office 9.5版本存在安全漏洞。攻击者利用该漏洞可以访问文件或目录。 漏洞编号&#xff1a;CVE-2023-2766 漏洞复现 FOFA语法&#xff1a; app"泛微-EOffice&qu…

快速走进通信世界 --- 基础知识扫盲

想不到吧&#xff0c;家人们&#xff0c;博主好久没来更新文章了&#xff0c;而且这次更新的是关于通信工程的文章。博主确实以前一直更新关于编程的文章&#xff0c;只不过最近在学习一些新的知识&#xff0c;以后有机会了我还是会继续更新一些编程技术文章的。不过每一门技术…

智慧工地源码:助力数字建造、智慧建造、安全建造、绿色建造

智慧工地围绕建设过程管理&#xff0c;建设项目与智能生产、科学管理建设项目信息生态系统集成在一起&#xff0c;该数据在虚拟现实环境中&#xff0c;将物联网收集的工程信息用于数据挖掘和分析&#xff0c;提供过程趋势预测和专家计划&#xff0c;实现工程建设的智能化管理&a…

在 Microsoft Word 中启用护眼模式

在 Microsoft Word 中启用护眼模式 在使用 Microsoft Word 365 或 Word 2019&#xff08;Windows&#xff09;版本时&#xff0c;启用护眼模式&#xff08;也称为“夜间模式”&#xff09;可以有效减轻屏幕亮度&#xff0c;有助于减少眼睛疲劳。以下是启用护眼模式的步骤&…

YOLOv5算法进阶改进(1)— 改进数据增强方式 + 添加CBAM注意力机制

前言:Hello大家好,我是小哥谈。本节课设计了一种基于改进YOLOv5的目标检测算法。首先在数据增强方面使用Mosaic-9方法来对训练集进行数据增强,使得网络具有更好的泛化能力,从而更好适用于应用场景。而后,为了更进一步提升检测精度,在backbone中嵌入了CBAM注意力机制模块,…

[100天算法】-面试题 04.01.节点间通路(day 72)

题目描述 节点间通路。给定有向图&#xff0c;设计一个算法&#xff0c;找出两个节点之间是否存在一条路径。示例1:输入&#xff1a;n 3, graph [[0, 1], [0, 2], [1, 2], [1, 2]], start 0, target 2 输出&#xff1a;true 示例2:输入&#xff1a;n 5, graph [[0, 1], …