首页 > 其他分享 >乐观锁与悲观锁

乐观锁与悲观锁

时间:2024-03-13 23:33:32浏览次数:18  
标签:事务 String int 乐观 static 悲观 balance 数据

乐观锁和悲观锁是处理数据库并发操作的两种不同策略

乐观锁

乐观锁的核心思想是“乐观”,它假设在数据处理过程中,冲突发生的概率较低。因此,乐观锁不会在事务开始时就锁定数据,而是在数据提交时检查是否有其他事务修改过这些数据。如果数据未被修改,则事务可以成功提交;如果数据被其他事务修改了,则当前事务需要重新执行或放弃。乐观锁通常通过版本号(version)或时间戳(timestamp)来实现,每次更新数据时,版本号或时间戳都会相应地增加。这样,当事务尝试更新数据时,它会检查版本号或时间戳是否与开始时相同,如果不同则说明数据已被其他事务修改。

import java.util.concurrent.TimeUnit;

public class OptimisticLockExample {
    private static int balance = 100;
    private static int version = 1;

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> updateBalance(50));
        Thread thread2 = new Thread(() -> updateBalance(30));

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        System.out.println("Final balance: " + balance);
    }

    public static void updateBalance(int amount) {
        int currentVersion = version;

        // 模拟业务逻辑,更新余额
        int newBalance = balance + amount;

        // 模拟其他事务可能对数据进行修改的情况
        try {
            TimeUnit.SECONDS.sleep(2); // 模拟等待2秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 检查版本号是否发生变化
        if (version == currentVersion) {
            // 没有变化,可以更新数据
            balance = newBalance;
            version++;
            System.out.println("Balance updated successfully!");
        } else {
            // 版本号发生变化,说明有其他事务修改了数据,需要回滚
            System.out.println("Data has been modified by another transaction. Rollback.");
        }
    }
}

悲观锁:

悲观锁是一种预防性的策略,它的核心思想是在数据被访问时加锁,以防止其他事务或进程同时修改同一数据。这通常通过数据库提供的锁机制来实现,确保在任一时刻只有一个事务能够对数据进行写操作。

悲观锁的实现通常涉及到数据库中的行级锁或表级锁。行级锁是锁定特定行,而表级锁则是锁定整张表。悲观锁在数据被读取时就加上锁,直到事务结束才会释放,这样可以保证在事务执行期间不会有其他事务对数据进行修改。这种机制适用于写操作频繁、冲突概率高的环境,因为它可以有效地防止冲突发生,但可能会影响并发性能。

与乐观锁相比,悲观锁在数据处理上更为保守,总是假设共享资源会被修改,因此它在数据操作前就加上锁。乐观锁则相反,它假设共享资源不会被修改,只在提交时验证。

悲观锁是一种更为保守的并发控制策略,适用于对数据一致性要求较高的情景。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class PessimisticLockExample {
    private static final String DB_URL = "jdbc:mysql://localhost:3306/mydatabase";
    private static final String DB_USER = "username";
    private static final String DB_PASSWORD = "password";

    public static void main(String[] args) {
        try (Connection connection = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD)) {
            connection.setAutoCommit(false); // 关闭自动提交

            // 获取悲观锁
            String selectQuery = "SELECT * FROM users WHERE id = 1 FOR UPDATE";
            PreparedStatement selectStatement = connection.prepareStatement(selectQuery);
            ResultSet resultSet = selectStatement.executeQuery();

            if (resultSet.next()) {
                int balance = resultSet.getInt("balance");
                int newBalance = balance + 50;

                // 更新余额
                String updateQuery = "UPDATE users SET balance = ? WHERE id = 1";
                PreparedStatement updateStatement = connection.prepareStatement(updateQuery);
                updateStatement.setInt(1, newBalance);
                updateStatement.executeUpdate();

                connection.commit(); // 提交事务
                System.out.println("Balance updated successfully!");
            } else {
                System.out.println("User not found.");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

上述示例中,我们使用了MySQL数据库作为示例。首先,我们通过FOR UPDATE子句获取了悲观锁,确保在事务执行期间不会有其他事务对数据进行修改。然后,我们执行查询操作并获取用户的余额信息。接下来,我们更新余额并提交事务。如果在事务执行期间有其他事务尝试修改同一行数据,将会被阻塞直到当前事务完成。 

标签:事务,String,int,乐观,static,悲观,balance,数据
From: https://blog.csdn.net/m0_59166601/article/details/136407559

相关文章

  • 乐观锁和悲观锁!!!
    概念乐观锁:乐观锁实在执行线程任务时,不会直接加锁,而是在数据记录中添加一个版本号。当事务需要更新数据时,它会检查版本号是否与之前读取时相同。如果相同,则执行更新操作;如果不同,则说明有其他事务在此期间修改了数据,当前事务需要重新执行读取和更新操作。悲观锁:悲观锁是在执行......
  • MySQL实战:解密乐观并发控制,确保数据操作不冲突
     概述:乐观并发控制是处理数据访问并发的一种策略,通过在更新前检查版本号或时间戳,确保数据在事务间保持一致性。在MySQL示例中,通过比对版本号,如果发现其他事务已更新数据,则拒绝当前事务的修改,避免潜在的并发冲突。这种机制提高了数据一致性,典型应用包括乐观锁的实现。数据访问......
  • 悲观锁和乐观锁
    最近面试都被问到这个,可是都只是靠着零散的记忆不知说了啥,那就好好整理一趟吧。悲观锁:当我们要对一个数据库中的一条数据进行修改的时候,为了避免同时被其他人需改,最好的方法就是直接对该数据进行加锁以防止并发。这种借助数据库锁机制在修改数据之前先锁定,再修改的方式称之为悲......
  • sqlserver 数据库事务ACID和使用 数据库锁,悲观锁乐观锁死锁
    在SQLServer中,事务的ACID属性、数据库锁、悲观锁、乐观锁和死锁是数据库管理和设计中的重要概念。以下是对这些概念的详细解释以及如何在SQLServer中使用它们:1.ACID属性在SQLServer中,事务必须满足ACID属性,以确保数据的一致性和可靠性。原子性(Atomicity):......
  • C#和sqlserver 如何实现 事务ACID和使用 数据库锁,悲观锁乐观锁死锁
    在C#中使用SQLServer实现事务的ACID(原子性、一致性、隔离性、持久性)属性和使用数据库锁(悲观锁和乐观锁)时,你可以通过ADO.NET的SqlConnection和SqlTransaction类来实现。下面是一些示例和概念说明。实现ACID事务ACID属性是事务处理的四个基本特征,它们确保事务在数据库中的正确......
  • MySQL乐观锁与悲观锁
    说明遇见并发情况,需要保证数据的准确性,也就是与正确的预期一致,此时就会用到锁。锁是在并发下控制程序的执行逻辑,以此来保证数据按照预期变动。如果不加锁,并发情况下的可能数据不一致的情况,这是个概率问题。乐观锁CAS简介乐观锁很乐观,假设数据一般情况不会造成冲突,属于程序层......
  • 使用悲观锁防止超卖问题
    记录一次使用悲观锁防止超卖的demo实例。环境配置可以参照我上篇笔记此处只展示核心代码 代码//先查库存Devicedevice=deviceMapper.selectByIdUpdate(3);//核心为该行代码//Thread.sleep(3000);if(device.getSortNum()>0){System.out.println("当前库存是:"+......
  • 一个小小的乐观锁、悲观锁也能扯这么多
    前言:我们一个普通的下单接口通常都包含如下三步操作,如果下单不成功的话将会返回给用户一个提示下单失败。查询库存(selectstockfromxxwhereid=xx)扣减更新库存(updatexxsetstock=stock-1whereid=xx)生成订单如果是只有一个用户来请求下单接口,那么上述的操作毫无疑问......
  • php redis 悲观锁
    悲观锁(PessimisticLock),顾名思义,就是每次处理redis数据都以最悲观的场景展开,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做......
  • 乐观锁和悲观锁
    悲观锁认为⾃⼰在使⽤数据的时候⼀定有别的线程来修改数据,因此在获取数据的时候会先加锁,确保数据不会被别的线程修改。synchronized关键字和Lock的实现类都是悲观锁适合写操作多的场景,先加锁可以保证写操作时数据正确。调用方式//=============悲观锁的调⽤⽅式publicsynch......