并发预订是指多个用户同时尝试预订同一资源,如酒店房间、航班座位等。为了解决并发预订的问题,可以使用以下方法之一:
// 使用悲观锁实现并发预订
public void bookRoom(String roomId, String userId) {
// 获取数据库连接
Connection connection = getConnection();
try {
// 开始事务
connection.setAutoCommit(false);
// 加锁,阻塞其他用户预订该房间
String sql = "SELECT * FROM rooms WHERE room_id = ? FOR UPDATE";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1, roomId);
statement.executeQuery();
// 检查房间是否已被预订
String checkSql = "SELECT * FROM bookings WHERE room_id = ? AND status = 'BOOKED'";
PreparedStatement checkStatement = connection.prepareStatement(checkSql);
checkStatement.setString(1, roomId);
ResultSet resultSet = checkStatement.executeQuery();
if (resultSet.next()) {
// 房间已被预订
throw new Exception("该房间已被预订");
} else {
// 预订房间
String insertSql = "INSERT INTO bookings (room_id, user_id, status) VALUES (?, ?, 'BOOKED')";
PreparedStatement insertStatement = connection.prepareStatement(insertSql);
insertStatement.setString(1, roomId);
insertStatement.setString(2, userId);
insertStatement.executeUpdate();
// 提交事务
connection.commit();
}
} catch (Exception e) {
// 发生异常时回滚事务
connection.rollback();
throw e;
} finally {
// 关闭数据库连接
connection.close();
}
}
// 使用乐观锁实现并发预订
public void bookRoom(String roomId, String userId) {
// 获取数据库连接
Connection connection = getConnection();
try {
// 开始事务
connection.setAutoCommit(false);
// 查询房间信息
String selectSql = "SELECT * FROM rooms WHERE room_id = ?";
PreparedStatement selectStatement = connection.prepareStatement(selectSql);
selectStatement.setString(1, roomId);
ResultSet resultSet = selectStatement.executeQuery();
if (resultSet.next()) {
int version = resultSet.getInt("version");
// 检查房间是否已被预订
String checkSql = "SELECT * FROM bookings WHERE room_id = ? AND status = 'BOOKED'";
PreparedStatement checkStatement = connection.prepareStatement(checkSql);
checkStatement.setString(1, roomId);
ResultSet checkResultSet = checkStatement.executeQuery();
if (checkResultSet.next()) {
// 房间已被预订
throw new Exception("该房间已被预订");
} else {
// 更新房间预订信息
String updateSql = "UPDATE rooms SET version = ?, status = 'BOOKED' WHERE room_id = ? AND version = ?";
PreparedStatement updateStatement = connection.prepareStatement(updateSql);
updateStatement.setInt(1, version + 1);
updateStatement.setString(2, roomId);
updateStatement.setInt(3, version);
int affectedRows = updateStatement.executeUpdate();
if (affectedRows == 0) {
// 更新失败,说明房间版本已变化,需要重新获取最新版本并尝试预订
throw new Exception("房间已被其他用户预订");
} else {
// 预订成功
String insertSql = "INSERT INTO bookings (room_id, user_id, status) VALUES (?, ?, 'BOOKED')";
PreparedStatement insertStatement = connection.prepareStatement(insertSql);
insertStatement.setString(1, roomId);
insertStatement.setString(2, userId);
insertStatement.executeUpdate();
// 提交事务
connection.commit();
}
}
} else {