首页 > 编程语言 >Java使用分布式锁来防止重复提交

Java使用分布式锁来防止重复提交

时间:2024-07-03 14:58:50浏览次数:21  
标签:Java String lockPath zookeeper public 锁来 节点 分布式

1.分布式锁使用场景

分布式锁的使用场景包括以下几个方面:

1)防止重复操作:在某些业务场景下,可能会出现多个客户端同时对同一资源进行修改或者访问的情况。为了避免这种情况发生,可以采用分布式锁来保证只有一个客户端能够成功获取到资源并执行相应操作。

2)控制并发流量:在高并发环境中,如果所有请求都直接访问后台服务,则很容易造成系统崩溃或者性能下降等问题。因此可以通过引入分布式锁机制来控制并发流量,并确保系统稳定运行。

3)任务调度与协作:在大规模分布式系统中,可能需要对各个节点上的任务进行统一管理和协调。此时可以利用分布式锁机制实现任务调度、负载均衡和故障恢复等功能。

4)数据库事务控制:在数据库事务处理过程中,为了防止数据不一致或者死锁等问题,通常需要采用分布式锁机制来保证事务正确执行。

总之,在任何需要对共享资源进行互斥访问、控制流量或者协作处理的场景下都可以考虑使用分布式锁技术。

2.使用Redisson实现分布式锁防止重复提交

步骤如下:

选择合适的分布式锁实现:常见的分布式锁实现包括ZooKeeper、Redis和基于数据库等。根据具体情况选择最佳方案。

获取分布式锁:在需要进行操作时,首先尝试获取分布式锁。如果成功获取到,则可以执行相应操作;否则说明已经有其他客户端正在处理该请求,此时可以直接返回或者等待一段时间后再次尝试。

执行业务逻辑:在获得了分布式锁之后,即可执行相应业务逻辑。例如,在Web应用中可以将表单数据保存到数据库中,并标记为已处理状态。

释放分布式锁:在完成所有操作之后,必须及时释放占用的资源(包括数据库连接、文件句柄等)以及释放所持有的分布式锁。

以下是一个简单示例代码演示如何使用Java实现基本的防止重复提交功能:

public class SubmitController {
    private static final String LOCK_KEY = "submit_lock";

    // Redisson客户端
    private RedissonClient redisson;

    // 初始化方法,在系统启动时执行
    public void init() throws Exception {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://localhost:6379");
        redisson = Redisson.create(config);
        System.out.println("SubmitController initialized.");
     }

     // 处理POST请求
     @PostMapping("/submit")
     public String submit(@RequestParam("data") String data) {
         RLock lock = redisson.getLock(LOCK_KEY);
         try{
             if(lock.tryLock()){
                 // 获得了排他性质的全局互斥访问权, 可以开始对共享资源进行修改。
                 saveDataToDatabase(data); 
             }else{
                 throw new RuntimeException("请勿重复提交!");
             }
         }finally{
            lock.unlock();
         }
      }

      // 将数据保存到数据库中并标记为已处理状态
      private void saveDataToDatabase(String data){
          Connection conn = null;
          PreparedStatement stmt = null;
          try{
              conn = getConnectionFromPool();  //从连接池中获取连接对象
              stmt=conn.prepareStatement(
                  "INSERT INTO my_table (data, is_processed) VALUES (?, ?)");
              stmt.setString(1,data);
              stmt.setBoolean(2,true);
              int rowsAffected=stmt.executeUpdate();
           }catch(SQLException ex){
               throw new RuntimeException(ex.getMessage(),ex);
           }finally{
               closeStatement(stmt);   //关闭语句对象  
               releaseConnection(conn);   //归还连接对象给连接池 
           }
       }
}

3.使用ZooKeeper实现分布式锁防止重复提交

以下步骤:

创建一个ZooKeeper客户端连接。

在ZooKeeper上创建一个持久节点作为锁的根节点,例如“/locks”。

当需要获取锁时,在“/locks”下创建一个临时顺序节点,并记录该节点的名称。例如,“/locks/lock-000001”。

获取所有子节点并按照顺序排序。

如果当前创建的临时顺序节点是第一个,则表示获得了锁;否则,监听前面一个子节点的删除事件,并等待通知。

释放锁时,删除自己创建的临时顺序节点即可。

代码示例:

public class DistributedLock {
    private final ZooKeeper zookeeper;
    private final String lockPath;

    public DistributedLock(ZooKeeper zookeeper, String lockPath) {
        this.zookeeper = zookeeper;
        this.lockPath = lockPath;
    }

    public void acquire() throws KeeperException, InterruptedException {
        // 创建临时顺序节点
        String path = zookeeper.create(lockPath + "/lock-", new byte[0], 
            ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        
        // 获取所有子节点并按照顺序排序
        List<String> children = zookeeper.getChildren(lockPath, false);
        Collections.sort(children);

        if (!path.equals(lockPath + "/" + children.get(0))) {
            // 如果当前不是最小编号,则监听前面一个子节点的删除事件
            int index = Collections.binarySearch(children, path.substring(path.lastIndexOf('/') + 1));
            String prevNodeName = children.get(index - 1);
            
            CountDownLatch latch = new CountDownLatch(1);
            
            Stat stat = zookeeper.exists(lockPath + "/" + prevNodeName,
                event -> { if (event.getType() == EventType.NodeDeleted) latch.countDown(); });
                
            if (stat != null) latch.await();
            
            acquire();
        }
    }

    public void release() throws KeeperException, InterruptedException {
         // 删除自己创建的临时顺序节
         zookeeper.delete(path, -1);    
     }
}

标签:Java,String,lockPath,zookeeper,public,锁来,节点,分布式
From: https://blog.csdn.net/shangjg03/article/details/140122157

相关文章

  • Java使用分布式锁来做分布式任务调度
    步骤如下:1) 选择合适的分布式锁实现:常见的分布式锁实现包括ZooKeeper、Redis和基于数据库等。根据具体情况选择最佳方案。2) 获取分布式锁:在需要进行操作时,首先尝试获取分布式锁。如果成功获取到,则可以执行相应操作;否则说明已经有其他客户端正在处理该请求,此时可以直......
  • Java编程从入门到放弃
    1.配置开发环境安装JDK官网下载地址:https://www.oracle.com/java/technologies/downloads/配置环境变量最新版本JDK22无需手动配置环境变量。老版本:此电脑-右键属性-高级系统设置-环境变量-系统变量-Path-编辑C:\Java\jdk1.8.0_65\bin检查结果java-versionHelloWor......
  • ArcGIS API for Javascript解决html2canvas、domtoimage截图地图出现空白问题
    原因使用html2canvas、domtoimage进行截图时,会出现地图面板是空白的情况,报错如下:#1133msUnabletocloneWebGLcontextasithaspreserveDrawingBuffer=false<canvasstyle=​"width:​100%;​height:​100%;​>在通过ArcGISAPIforJavaScript4.X版本实例化地图的......
  • Java 流式编程详解,Demo案例解析
    Java流式编程详解,Demo案例解析JavaStreams在很多年前就被引入了,但作为Java开发者,我们还没有完全掌握这个多功能工具的威力。在这里,你将发现一些有价值的技巧,可以作为参考并应用到你的下一个项目中。在下面的示例中,我们将使用以下类。@GetterclassCompany{privat......
  • 基于Java的宠物领养管理系统
    目录        一、系统简介1.需求分析2 .编程环境与工具二、系统总体设计1.系统的功能模块图2.系统架构3.系统部署和测试步骤4.各功能模块简介(1)主页:(2)宠物知识:(3)领养中心:(4)团队博客:(5)团队展示:(6)注册/登录:三、主要业......
  • 【Java完整版 面试必备】Leetcode Top100题目和答案-矩阵篇
    目录以下摘自leetcodeTop100精选题目-矩阵篇​矩阵置零螺旋矩阵旋转图像搜索二维矩阵II以下摘自leetcodeTop100精选题目-矩阵篇矩阵置零给定一个 mxn 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。示例:输入:matrix......
  • JAVA妇产科专科电子病历系统源码,前端框架:Vue,ElementUI
    JAVA妇产科专科电子病历系统源码,前端框架:Vue,ElementUI孕产妇健康管理信息管理系统是一种将孕产妇健康管理信息进行集中管理和存储的系统。通过建立该系统,有助于提高孕产妇健康管理的效率和质量,减少医疗事故发生的可能性,管理医疗资源,保证孕产妇得到及时、准确的医疗服务。该系......
  • java的常用技术
    1、java集合(Iterable、List、Set、Map,JUC安全性集合)2、hashmap(原理,延申)、ConcurrentHashMap(锁:1.8是synchronized+node,1.7是segment)3、乐观锁(比较/交换)AtomicInteger是Java中的一个原子类4、悲观锁synchronized5、线程池运行状态运行过程其他......
  • Java中semaphore的具体解释产生原因和使用场景
    Semaphore(信号量)信号量(Semaphore)是一种用于控制多个线程对共享资源访问的同步机制。它实质上是一个计数器,可以用来限制能够访问某些资源的线程数量。信号量可以是二进制的(只允许一个线程访问)或计数的(允许多个线程访问,具体数目由信号量的值决定)。信号量产生的原因信号量最......
  • Java基础——常用类库
    在Java编程的世界里,掌握并熟练使用类库是提高开发效率和代码质量的关键。本文将深入探讨几个常用的Java类库,包括它们的功能、应用场景以及如何有效利用它们来优化你的项目。1. CollectionsFramework简介:Java的集合框架(CollectionsFramework)提供了实现数据结构如列表、集......