java - JDBC 和并发问题

标签 java mysql database jdbc concurrency

我想要一些关于 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();
}

此时,如果另一个用户试图同时更新同一条记录,则此连接将等待或超时,因此您必须为这两种情况做好准备。在您的事务结束(提交或回滚)之前,记录不会被解锁。

然后,您可以安全地选择和更新您想要的任何内容,并确保在您处理数据时没有其他人接触您的记录。如果其他人尝试,他们将等待您完成(或者他们将超时,具体取决于连接配置)。

或者,您可以使用乐观锁定。在这种情况下,您读取您的记录,对其进行修改,但在更新中,您通过检查版本/时间戳字段是否与您最初读取的相同来确保自您读取它以来没有其他人更改过它。在这种情况下,如果您意识到您有陈旧/过时的数据,您必须准备好重试事务(或一起中止它)。

更新表集合=?在哪里 id=?和版本=1

如果受影响的行数为 0,则您知道记录很可能在您的读取和更新之间更新,并且该记录不再是版本 1。

关于java - JDBC 和并发问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14255565/

相关文章:

java - 将一个调用 java 程序的响应传递给另一个

php - MySQL + PHP : HTML Style

php - 拉拉维尔 5.6 : Many-to-many relationship returns empty object

php - 根据ID显示所有字段

java - 在 Java 中动态更改 ResourceBundle Locale

java - 动态行为如何改变 Java 中的状态?

java - 没有迭代的过滤列表

mysql - 子查询总是返回单条记录

mysql - 如何递归填充子类别?

php - 如何使用外键连接 3 个表