Java中JDBC事务通过version字段实现乐观锁,核心是UPDATE语句中WHERE校验旧version且SET中version+1,executeUpdate()返回0表示失败,需抛异常或重试,并确保读-改-写在同一事务内完成。

Java 中结合版本号字段在 JDBC 事务中实现乐观锁,核心是在 SQL 更新语句中加入 version 字段校验,由数据库层面保证并发更新的原子性。只要事务提交时发现版本不匹配,就说明数据已被其他事务修改,当前更新应失败并由应用层决定重试或提示。
数据库表结构需包含 version 字段
乐观锁依赖数据库中一个单调递增的整数字段(如 version),通常为 TINYINT、SMALLINT 或 INT 类型,默认值为 0。该字段不参与业务逻辑,仅用于并发控制。
- 建表示例:
CREATE TABLE account (id BIGINT PRIMARY KEY, balance DECIMAL(10,2), version INT NOT NULL DEFAULT 0); - 每次成功更新后,version 自动 +1,且只在 WHERE 条件中校验旧值
UPDATE 语句必须带 version 条件和自增
执行更新时,SQL 必须同时满足两个条件:① 主键或唯一条件匹配;② 当前记录的 version 等于读取时的旧值。更新成功后 version 加 1。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 正确写法:
UPDATE account SET balance = ?, version = version + 1 WHERE id = ? AND version = ?; - JDBC 中用
PreparedStatement绑定参数:balance 新值、id、读取时的 version 值 - 通过
executeUpdate()返回值判断是否更新成功(返回 1 表示成功,0 表示被其他事务抢先修改)
Java 代码中封装乐观锁更新逻辑
在 Service 层或 DAO 层统一处理 version 校验失败场景,避免裸 SQL 散布各处。
立即学习“Java免费学习笔记(深入)”;
- 查询时务必查出当前 version 值:
SELECT id, balance, version FROM account WHERE id = ? - 更新失败时不要静默吞掉,应抛出自定义异常(如
OptimisticLockException)或返回失败标识 - 若业务允许,可支持有限次数自动重试(需注意避免无限循环或脏读)
事务边界与连接管理要明确
乐观锁本身不依赖长事务,但需确保“读-改-写”过程在同一个 JDBC 连接中完成,且整个操作包裹在事务内(即使只有一条 UPDATE,也建议显式开启事务)。
- 使用
Connection.setAutoCommit(false)开启事务,失败时rollback(),成功后commit() - 不要跨多次数据库往返读取再更新——version 必须是本次事务中刚查到的值
- 连接池中获取的 Connection 需手动管理事务,Spring 的
@Transactional可自动代理,但仍需保证 SQL 正确携带 version 条件

















