[英]JDBC and Concurrency issues
我想要一些有关jdbc的并发问题的建议,我基本上需要先更新一个值,然后使用更新再进行选择来检索该值,我假设通过关闭自动提交功能,其他事务都无法访问该表,因此其他事务在提交更新之前,将无法执行更新和选择查询。
下面是一些示例代码。 您认为这会行得通吗,还有其他人对此有更好的解决方案吗?
int newVal=-1;
con.setAutoCommit(false);
PreparedStatement statement = con.prepareStatement("UPDATE atable SET val=val+1 WHERE id=?");
statement.setInt(1, id);
int result = statement.executeUpdate();
if (result != 1) {
throw new SQLException("Nothing updated");
} else {
statement = con.prepareStatement("SELECT val FROM atable WHERE id=?");
statement.setInt(1, id);
ResultSet resultSet = statement.executeQuery();
if (resultSet.next()) {
newVal = resultSet.getInt("val");
}
}
statement.close();
con.commit();
con.setAutoCommit(true);
谢谢。
假设您使用某种形式的数据源,则可以在此处进行配置,以获取事务性和隔离级别。 但要明确:
try(Connection con = ds.getConnection()){
con.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
con.setAutoCommit(false);
//...
} catch(SQLException sqle) {
throw new MyModelException(e)
}
现在,您可以通过更新表中的版本(或时间戳)字段来触发悲观锁定。 这将触发数据库中的锁定(最有可能在记录级别):
try(PreparedStatement pStm = con.prepareStatement("update atable set version=version+1")){
pStm.executeUpdate();
}
此时,如果另一个用户试图同时更新同一条记录,则此连接将等待或超时,因此您必须为这两件事做好准备。 直到交易结束(提交或回滚),记录才会解锁。
然后,您可以安全地选择和更新所需的内容,并确保在处理数据时没有其他人触摸您的记录。 如果有其他人尝试,则将等待您完成操作(否则它们将超时,具体取决于连接配置)。
或者,您可以使用乐观锁定。 在这种情况下,您可以读取记录,并对其进行修改,但是在更新中,请确保您没有其他人更改过记录,因为您通过检查版本/时间戳字段与您最初读取的记录/字段相同来对其进行了更改。 在这种情况下,如果您意识到数据已过时/过时,则必须准备重试事务(或将其全部中止)。
即update atable set afield=? where id=? and version=1
update atable set afield=? where id=? and version=1
如果受影响的行数为0,则您知道该记录很可能在读取和更新之间进行了更新,并且该记录不再处于版本1中。
在连接上设置autocommit=false
不会阻止其他连接/线程更改数据库中的行! 仅在该特定连接上的每个JDBC操作之后,它才会禁用自动提交。
您将需要锁定该行,例如。 使用select ... for update
以防止针对该行进行其他事务,并且您还需要在单个事务中进行选择和更新。
干杯,
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.