乐观锁-版本号实现方式

乐观锁-版本号

实现策略:提交版本号必须大于数据库表记录的版本号才能执行

举例:比如下面是一张表,最后加一个版本号

idnameversion
1全栈独立开发者1
   

然后,两个线程,比如线程A,线程B,同时取id=1得记录。这个时候两个线程版本号都是1。

接下来,线程A修改了name和version自增,提交事务。这个时候update的语句应该如下:

update 表 set name='全栈开发' ,version=version+1 where id=1 and  version <2 (sql应该这样写的,不记得了^^) ,执行成功 数据库表的id=1这条记录versoin=2了。

在接下来,由于线程B这家伙动作比较慢,等线程A已经提交了,然后执行Update

update 表 set name='全栈开发' ,version=version+1 where  id=1 and version <2 , 发现执行不了了。失败。

### Java MySQL 实现基于版本号乐观锁 为了在Java中使用MySQL实现基于版本号乐观锁,可以通过以下方式来确保并发控制的有效性。下面提供了一个完整的示例代码,展示了如何利用版本号字段 `version` 来防止多个事务同时修改同一行数据。 #### 创建带有版本号的数据表 首先,在数据库中创建一张包含版本号字段的表格: ```sql CREATE TABLE products ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255), stock INT NOT NULL DEFAULT 0, version INT NOT NULL DEFAULT 0 ); ``` #### 插入初始数据 向表中插入一些测试数据: ```sql INSERT INTO products (name, stock) VALUES ('Product A', 10), ('Product B', 20); ``` #### 编写Java代码实现乐观锁逻辑 以下是具体的Java代码实现,用于查询并更新产品库存的同时应用乐观锁定策略: ```java import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; public class OptimisticLockingExample { private static final String DB_URL = "jdbc:mysql://localhost:3306/your_database"; private static final String USER = "root"; // 替换成自己的用户名 private static final String PASS = ""; // 替换成自己的密码 public static void main(String[] args) { try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS)) { int productId = 1; // 假设要操作的产品ID为1 // 查询现有记录及其版本号 Product product = findProductById(conn, productId); System.out.println("尝试减少商品数量:" + product.getName()); boolean success = reduceStock(conn, product.getId(), product.getVersion()); if (success) { System.out.println("减库存成功!"); } else { System.out.println("减库存失败:该条目已被其他事务更改"); } } catch (Exception e) { e.printStackTrace(); } } /** * 根据ID获取指定产品的信息以及其版本号 */ private static Product findProductById(Connection conn, int id) throws Exception { String sql = "SELECT id, name, stock, version FROM products WHERE id=?"; try (PreparedStatement stmt = conn.prepareStatement(sql)) { stmt.setInt(1, id); ResultSet rs = stmt.executeQuery(); while (rs.next()) { return new Product( rs.getInt("id"), rs.getString("name"), rs.getInt("stock"), rs.getInt("version") ); } } throw new RuntimeException("未找到对应的商品"); } /** * 尝试减少指定产品的库存量,并检查是否有冲突发生 */ private static boolean reduceStock(Connection conn, int id, int expectedVersion) throws Exception { String sql = "UPDATE products SET stock = stock - 1, version = ? WHERE id = ? AND version = ?"; try (PreparedStatement stmt = conn.prepareStatement(sql)) { int nextVersion = expectedVersion + 1; stmt.setInt(1, nextVersion); stmt.setInt(2, id); stmt.setInt(3, expectedVersion); int affectedRows = stmt.executeUpdate(); return affectedRows == 1; } } } class Product { private int id; private String name; private int stock; private int version; public Product(int id, String name, int stock, int version) { this.id = id; this.name = name; this.stock = stock; this.version = version; } public int getId() {return id;} public String getName() {return name;} public int getStock() {return stock;} public int getVersion() {return version;} } ``` 此段代码实现了如下功能: - 使用 `findProductById()` 方法从数据库中检索特定 ID 的产品详情及当前版本号- 调用 `reduceStock()` 函数尝试将选定产品的库存数减一,并验证所提供的预期版本号是否匹配实际存储于数据库内的版本号。只有当两者相等时才会执行更新操作;否则返回 false 表明存在并发冲突[^4]。
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值