Java 说一下乐观锁和悲观锁?

Java 说一下乐观锁和悲观锁?

乐观锁和悲观锁是并发控制中两种不同的思想和实现方式。

  1. 悲观锁:

    • 思想: 假设在并发情况下会发生冲突,因此在整个操作过程中都认为会有其他事务来修改数据,因此在数据操作之前先加锁,确保自己操作时不会被其他事务干扰。
    • 实现方式: 使用数据库的行级锁(例如 SELECT ... FOR UPDATE)或使用 Java 中的同步锁(例如 synchronized 关键字)来保证数据的一致性。
    • 示例代码: 使用数据库行级锁的悲观锁。
      // 使用 SELECT ... FOR UPDATE 加行级锁
      Connection connection = dataSource.getConnection();
      connection.setAutoCommit(false);
      
      try {
          PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM my_table WHERE id = ? FOR UPDATE");
          preparedStatement.setInt(1, desiredId);
          ResultSet resultSet = preparedStatement.executeQuery();
      
          // 进行数据更新操作
      
          connection.commit();
      } catch (SQLException e) {
          connection.rollback();
      } finally {
          connection.setAutoCommit(true);
          connection.close();
      }
      
  2. 乐观锁:

    • 思想: 假设在并发情况下不会发生冲突,因此在整个操作过程中都不加锁,只在更新数据时检查在此期间是否有其他事务对数据进行了修改,如果有则取消操作,重新尝试。
    • 实现方式: 使用版本号(或时间戳)进行标记,在更新数据时检查版本号,如果版本号不一致则认为数据已被其他事务修改。
    • 示例代码: 使用版本号的乐观锁。
      // 数据库表结构包含 version 字段
      CREATE TABLE my_table (
          id INT PRIMARY KEY,
          name VARCHAR(50),
          version INT
      );
      
      // Java 代码中使用版本号进行乐观锁
      Connection connection = dataSource.getConnection();
      connection.setAutoCommit(false);
      
      try {
          PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM my_table WHERE id = ?");
          preparedStatement.setInt(1, desiredId);
          ResultSet resultSet = preparedStatement.executeQuery();
      
          // 获取数据并检查版本号
          if (resultSet.next()) {
              int currentVersion = resultSet.getInt("version");
              // 进行数据更新操作,更新时同时更新版本号
              PreparedStatement updateStatement = connection.prepareStatement("UPDATE my_table SET name = ?, version = ? WHERE id = ? AND version = ?");
              updateStatement.setString(1, newName);
              updateStatement.setInt(2, currentVersion + 1);
              updateStatement.setInt(3, desiredId);
              updateStatement.setInt(4, currentVersion);
              int updatedRows = updateStatement.executeUpdate();
              if (updatedRows == 0) {
                  // 更新失败,可能有其他事务修改了数据,可以进行回滚或重试
              }
          }
      
          connection.commit();
      } catch (SQLException e) {
          connection.rollback();
      } finally {
          connection.setAutoCommit(true);
          connection.close();
      }
      

在实际应用中,选择悲观锁还是乐观锁取决于应用的并发访问模式、性能要求以及业务逻辑的复杂性。乐观锁通常在读多写少的场景中表现较好,而悲观锁适用于写多读少、事务较为复杂的场景。

  • 21
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学习资源网

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值