乐观锁和悲观锁是并发控制中两种不同的思想和实现方式。
悲观锁:
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();
}
乐观锁:
// 数据库表结构包含 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();
}
在实际应用中,选择悲观锁还是乐观锁取决于应用的并发访问模式、性能要求以及业务逻辑的复杂性。乐观锁通常在读多写少的场景中表现较好,而悲观锁适用于写多读少、事务较为复杂的场景。