redis的应用,缓存,分布式锁

1.应用

1.1可以用作缓存

作用:提交数据的查询效率,减少对数据库的访问频率

什么数据适合放入缓存

1.查询频率高,修改频率低

2.对安全系数比较低

 如何实现

@Service
public class DeptServer {
    @Autowired
    private DeptMapper deptMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    public Dept selectById(Integer id){
        //查询是否在缓存
        ValueOperations forValue = redisTemplate.opsForValue();
        Object o = forValue.get("dept::" + id);
        if(o!=null){
            return (Dept) o;
        }
        Dept dept = deptMapper.selectById(id);
        //存储缓存
        forValue.set("dept::" + id,dept);
        return dept;
    }
}

1.1.2缓存注解

spring4.0以后,提供了缓存注解,可以使用注解完成缓存功能,无需自己写

1.在配置类中添加缓存配置

 @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory){
        RedisSerializer<String> redisSerializer=new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer=new Jackson2JsonRedisSerializer(Object.class);
        //解决缓存查询转换异常问题
        ObjectMapper om=new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        //配置序列化(解决乱码的问题),过期时间600s
        RedisCacheConfiguration config=RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(600))//设置过期时间
                //设置key序列化方式
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                //设置value序列化方式
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();
        RedisCacheManager cacheManager=RedisCacheManager.builder(factory).cacheDefaults(config).build();
        return cacheManager;
     }

2.使用注解@Cacheable

@Service
public class DeptServer {
    @Autowired
    private DeptMapper deptMapper;
    //@Cacheable针对查询的,缓存名为"dept::"+id,它的value为返回结果,返回结果为null则不存入,否则存入
    @Cacheable(value = "dept",key = "#id")
    public Dept selectById(Integer id){
        Dept dept = deptMapper.selectById(id);
        return dept;
    }
}

3.开启缓存注解

package com.ghx.server;

import com.ghx.dao.DeptMapper;
import com.ghx.pojo.entity.Dept;
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;

/**
 * @author :guo
 * @date :Created in 2025/2/18 14:22
 * @description:
 * @version:
 */
@Service
public class DeptServer {
    @Autowired
    private DeptMapper deptMapper;
    //@Cacheable针对查询的,缓存名为"dept::"+id,它的value为返回结果,返回结果为null则不存入,否则存入
    @Cacheable(value = "dept",key = "#id")
    public Dept selectById(Integer id){
        Dept dept = deptMapper.selectById(id);
        return dept;
    }
    //先执行方法体,再删除缓存
    @CacheEvict(value = "dept",key = "#id")
    public int delete(Integer id){
        return deptMapper.deleteById(id);
    }

    //先修改数据库,再修改缓存,把dept对象存入
    @CachePut(value = "dept",key = "#dept.id")
    public Dept update(Dept dept){
        deptMapper.updateById(dept);
        return dept;
    }

}
package com.ghx.controller;

import com.ghx.pojo.entity.Dept;
import com.ghx.server.DeptServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * @author :guo
 * @date :Created in 2025/2/18 14:24
 * @description:
 * @version:
 */
@RestController
public class DeptController {
    @Autowired
    private DeptServer deptServer;

    @GetMapping("selectById/{id}")
    public Dept selectById(@PathVariable Integer id) {
        //@PathVariable获取请求参数的{}参数
        return deptServer.selectById(id);
    }

    @GetMapping("delete/{id}")
    public int delete(@PathVariable Integer id) {
        return deptServer.delete(id);
    }

    @PutMapping("update")
    public Dept update(@RequestBody Dept dept) {
        return deptServer.update(dept);
    }
}

1.1.3缓存注解

@Cacheable针对查询的,缓存名如"dept::"+id,它的value为返回结果,返回结果为null则不存入,否则存入
@CacheEvict先执行方法体,再删除缓存
@CachePut先修改数据库,再修改缓存,把dept对象存入

1.2可以作为分布式锁

synchronized:

lock:接口

        实现类:

        ReentrantLock:重入锁
        ReentrantReadWriteLock:读写分离锁

                        加的为读锁则线程不堵塞

                        加的是写锁线程堵塞

上面的都是本地锁

本地锁

 //如果在单线程下---该功能没有任何问题。
    //如果在多线程的情况---jmeter压测工具---发现出现线程安全问题了。==使用锁synchronized ()或lock锁。
    //发现使用锁之前没有问题了。但是如果该项目是一个集群。--发现在集群的情况下本地锁【只对当前工程有效】无效了。
    //解决方案就是集群工程共用一把锁就行。---可以使用redis来解决问题。
public String decrement(Integer productid) {
        //根据id查询商品的库存
        synchronized (this) {
            int num = stockDao.findById(productid);
            if (num > 0) {
                //修改库存
                stockDao.update(productid);
                System.out.println("商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个");
                return "商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个";
            } else {
                System.out.println("商品编号为:" + productid + "的商品库存不足。");
                return "商品编号为:" + productid + "的商品库存不足。";
            }
        }
    }

手动实现

@Autowired
    private StringRedisTemplate redisTemplate;


    public String decrement(Integer productid) {
        ValueOperations<String,String> forValue = redisTemplate.opsForValue();
        //判断是否获取锁   如果程序死机了 ,无法执行完成
        //如果代码没有执行完成,会释放锁。      ——开启了一个守护线程,每隔10s检查当前线程是否还持有锁,如果当前线程还持有锁,就重新为当前线程分配30s
        //分配3次,33次后直接释放锁
        Boolean aBoolean = forValue.setIfAbsent("product::" + productid, "~~~~");
        if(aBoolean) {
            try {
                //根据id查询商品的库存
                int num = stockDao.findById(productid);
                if (num > 0) {
                    //修改库存
                    stockDao.update(productid);
                    System.out.println("商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个");
                    return "商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个";
                } else {
                    System.out.println("商品编号为:" + productid + "的商品库存不足。");
                    return "商品编号为:" + productid + "的商品库存不足。";
                }
            } finally {
                redisTemplate.delete("product::" + productid);
            }

        }
        System.out.println("服务器正忙");
        return "服务器正忙";
    }

 Redisson

 每隔10s检查当前线程是否还持有锁,如果当前线程还持有锁,就重新为当前线程分配30s

依赖

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.24.3</version>
</dependency>
@Autowired
    private RedissonClient redissonClient;

    public String decrement(Integer productid) {
        RLock lock = redissonClient.getLock("product::" + productid);

        try {
            //必须为30s
            lock.lock(30, TimeUnit.SECONDS);
                //根据id查询商品的库存
                int num = stockDao.findById(productid);
                if (num > 0) {
                    //修改库存
                    stockDao.update(productid);
                    System.out.println("商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个");
                    return "商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个";
                } else {
                    System.out.println("商品编号为:" + productid + "的商品库存不足。");
                    return "商品编号为:" + productid + "的商品库存不足。";
                }
        } finally {
             lock.unlock();
        }

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

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

相关文章

Ubuntu22.04 - etcd的安装和使用

目录 介绍安装Etcd安装etcd的客户端使用 介绍 Etcd 是一个 golang 编写的分布式、高可用的一致性键值存储系统&#xff0c;用于配置共享和服务发现等。它使用 Raft 一致性算法来保持集群数据的一致性&#xff0c;且客户端通过长连接watch 功能&#xff0c;能够及时收到数据变化…

对学习编程语言的一些理解

目录 一、代码运行的过程 二、跨平台的实现 1&#xff09;C/C 2&#xff09;C# 3&#xff09;Java 三、总结 一、代码运行的过程 开发程序无论使用何种编程语言&#xff0c;至少都需要经历编码、编译、连接和运行这么4个过程&#xff0c;C语言是这样&#xff0c;Java语言…

【知识】深度学习中,应该先zero_grad还是先backward?

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 目录 抛出问题 各大GPT的回答 ChatGPT-4o ChatGPT-o3-mini-high Kimi-长思考 Deepseek-R1 Grok3 Pytorch官方教程中 抛出问题 以下哪种方式是…

kafka消费能力压测:使用官方工具

背景 在之前的业务场景中&#xff0c;我们发现Kafka的实际消费能力远低于预期。尽管我们使用了kafka-go组件并进行了相关测试&#xff0c;测试情况见《kafka-go:性能测试》这篇文章。但并未能准确找出消费能力低下的原因。 我们曾怀疑这可能是由我的电脑网络带宽问题或Kafka部…

蓝桥云客 路径之谜

11.路径之谜 - 蓝桥云课 路径之谜 题目描述 小明冒充X星球的骑士&#xff0c;进入了一个奇怪的城堡。 城堡里边什么都没有&#xff0c;只有方形石头铺成的地面。 假设城堡地面是nn个方格。如下图所示。 按习俗&#xff0c;骑士要从西北角走到东南角。可以横向或纵向移动&…

Oracle 深入理解Lock和Latch ,解析访问数据块全流程

Oracle 锁机制介绍 根据保护对象的不同&#xff0c;单实例Oracle数据库锁可以分为以下几大类&#xff1a; DML lock&#xff08;data locks&#xff0c;数据锁&#xff09;&#xff1a;用于保护数据的完整性&#xff1b; DDL lock&#xff08;dictionary locks&#xff0c;字典…

Jenkins 环境搭建---基于 Docker

前期准备 提前安装jdk、maven、nodeJs&#xff08;如果需要的话&#xff09; 创建 jenkins 环境目录&#xff0c;用来当做挂载卷 /data/jenkins/ 一&#xff1a;拉取 Jenkins 镜像 docker pull jenkins/jenkins:lts 二&#xff1a;设置 Jenkins挂载目录 mkdir -p ~/jen…

DOS网络安全

ping -t 不间断地ping目标主机&#xff0c;直到用户用ctrlc键强行终止。经常用来排除网络故障 -l 定制ping信息包的容量,最大上限是65500字节 -n 向远程主机发送的数据 包个数&#xff0c;默认是4。 语法&#xff1a; ping 参数 IP地址 netstat -a 显示所有连接…

QML Component 与 Loader 结合动态加载组件

在实际项目中&#xff0c;有时候我们写好一个组件&#xff0c;但不是立即加载出来&#xff0c;而是触发某些条件后才动态的加载显示出来&#xff0c;当处理完某些操作后&#xff0c;再次将其关闭掉&#xff1b; 这样的需求&#xff0c;可以使用 Component 包裹着组件&#xff…

在 Mac ARM 架构的 macOS 系统上启用 F1 键作为 Snipaste 的截屏快捷键

在 Mac ARM 架构的 macOS 系统上启用 F1 键作为 Snipaste 的截屏快捷键&#xff0c;主要涉及到两个方面&#xff1a;确保 F1 键作为标准功能键工作 和 在 Snipaste 中设置 F1 为快捷键。 因为 Mac 默认情况下&#xff0c;F1-F12 键通常用作控制屏幕亮度、音量等系统功能的快捷键…

vue3学习1

vite是新的官方构建工具&#xff0c;构建速度比webpack更快 vue项目的入口文件是index.html&#xff0c;一般在这里引入src/main.js&#xff0c;并且设置好容器#app App.vue放的是根组件&#xff0c;components里放分支组件 vue组件中写三种标签&#xff0c;template & s…

istio实现灰度发布,A/B发布, Kiali网格可视化(二)

代码发布是软件开发生命周期中的一个重要环节&#xff0c;确保新功能和修复能够顺利上线。以下是几种常见的代码发布流程。在学习灰度发布之前。我们首先回忆下代码发布常用的几种方法。 A/B&#xff08;蓝绿&#xff09;发布&#xff1a; 蓝绿部署是一种通过维护两套独立的环…

MySQL日志undo log、redo log和binlog详解

MySQL 日志&#xff1a;undo log、redo log、binlog 有什么用&#xff1f; 一、前言 在MySQL数据库中&#xff0c;undo log、redo log和binlog这三种日志扮演着至关重要的角色&#xff0c;它们各自承担着不同的功能&#xff0c;共同保障了数据库的正常运行和数据的完整性。了解…

DeepSeek接入Siri(已升级支持苹果手表)完整版硅基流动DeepSeek-R1部署

DeepSeek接入Siri&#xff08;已升级支持苹果手表&#xff09;完整版硅基流动DeepSeek-R1部署 **DeepSeek** 是一款专注于深度学习和人工智能的工具或平台&#xff0c;通常与人工智能、机器学习、自动化分析等领域有关。它的主要功能可能包括&#xff1a;深度学习模型搜索&…

电力通信物联网应用,国密网关守护电力数据安全

电力国密网关是用于保护电力调度数据网路由器和电力系统的局域网之间通信安全的电力专用网关机&#xff0c;主要为上下级控制系统之间的广域网通信提供认证与加密服务&#xff0c;实现数据传输的机密性、完整性。 国密算法网关功能特点 身份认证&#xff1a;对接入的设备和用户…

overflow-x: auto 使用鼠标实现横向滚动,区分触摸板和鼠标滚动事件的方法

假设一个 div 的滚动只设置了 overflow-x: auto 我们发现使用鼠标的滚轮是无法左右滚动的&#xff0c;但是使用笔记本电脑的触摸板&#xff0c;或者在移动设备上是可以滚动的。所以我们需要兼容一下鼠标的横向滚动功能。 我们可以监控 wheel 事件&#xff0c;然后根据位置来计…

基于STM32单片机的智能蔬菜大棚温湿度监测系统设计

引言 在现代农业生产中&#xff0c;温湿度、光照强度和土壤湿度等环境因素对植物的生长起着至关重要的作用。智能蔬菜大棚正是基于这些因素&#xff0c;通过自动化控制和远程监控技术&#xff0c;实现对植物生长环境的精准管理&#xff0c;最终提升蔬菜的产量和质量。本文介绍…

【git-hub项目:YOLOs-CPP】本地实现05:项目移植

ok&#xff0c;经过前3个博客&#xff0c;我们实现了项目的跑通。 但是&#xff0c;通常情况下&#xff0c;我们的项目都是需要在其他电脑上也跑通&#xff0c;才对。 然而&#xff0c;经过测试&#xff0c;目前出现了2 个bug。 项目一键下载【⬇️⬇️⬇️】&#xff1a; 精…

Python实战:Excel中文转拼音工具开发教程

在日常办公中&#xff0c;我们经常需要处理Excel文件&#xff0c;有时候需要将中文转换为拼音缩写以方便检索和使用。今天我将分享一个使用Python开发的小工具&#xff0c;它可以自动将Excel文件中指定列的中文转换为拼音缩写。 C:\pythoncode\new\ConvertExcelcontentToPinyin…

新一代MPP数据库:StarRocks

文章目录 1.StarRocks简介2.StarRocks 在数据生态的定位3.StartRocks的使用场景3.1 实时数据仓库3.2 高并发查询3.3 日志与事件分析3.4 物联网&#xff08;IoT&#xff09;数据分析3.5 金融风控与实时监控3.6 数据湖查询加速3.7 A/B 测试与实验分析 4.StarRocks与MySQL比较4.1 …