Java sql读取+;写-防止竞争条件?

Java sql读取+;写-防止竞争条件?,java,mysql,Java,Mysql,我有两个线程调用一个方法,该方法在mysql数据库中执行记录的读取和写入。一些伪代码: public void incrementRowValue() { Connection conn = ...; try { conn.setAutoCommit(false); int value = conn.execute("select value from foo where id = 123"); value += 1;

我有两个线程调用一个方法,该方法在mysql数据库中执行记录的读取和写入。一些伪代码:

public void incrementRowValue() {
    Connection conn = ...;
    try {
        conn.setAutoCommit(false);

        int value = conn.execute("select value from foo where id = 123");
        value += 1;
        conn.execute("update foo set value = " + value + " where id = 123");  

        conn.commit();
    }
    catch (SQLException ex) {
        conn.rollback(); 
    }
    finally {
        conn.close();
    }
} 
因此,如果线程大约同时执行,则看起来读+写并不是作为一个原子项执行的。例如,当起始值为零时,我的日志显示,如果两个线程几乎同时执行,则结束值可以是1而不是2

我是否可以使用不同的锁定级别来防止这种情况?当然,如果必要的话,我可以用java代码进行同步,但我可能缺少了数据库级别为我们提供的一个重要特性

谢谢


最简单的方法是将SQL封装到一条语句中,让SQL server来处理它,我一时记不起确切的语法,但它可能是这样的:

    conn.execute("update foo set value = (select value from foo where id = 123)+1 where id = 123");  
SQL server将锁定正在使用的行(如果使用多行,将锁定所有行),并以原子方式执行操作


这也将更快/更高效,因为它只进行一次数据库调用,而不是两次。不过,这种更新实际上需要包装到存储过程中。

最简单的方法是将SQL包装到一个语句中,让SQL server处理它,我一时记不起确切的语法,但它可能类似于:

    conn.execute("update foo set value = (select value from foo where id = 123)+1 where id = 123");  
You can manage database concurrency using isolation levels

Isolation Level     Dirty Read  Nonrepeatable Read  Phantom Read
READ UNCOMMITTED    Permitted   Permitted   Permitted
READ COMMITTED  --  Permitted   Permitted
REPEATABLE READ     --  --  Permitted
SERIALIZABLE

SERIALIZABLE-it provide highest level of concurrency

For details please  refer :

[http://www.oracle.com/technetwork/issue-archive/2005/05-nov/o65asktom-082389.html][1] 
SQL server将锁定正在使用的行(如果使用多行,将锁定所有行),并以原子方式执行操作


这也将更快/更高效,因为它只进行一次数据库调用,而不是两次。不过,这种更新实际上需要包装到存储过程中。

最简单的方法是将SQL包装到一个语句中,让SQL server处理它,我一时记不起确切的语法,但它可能类似于:

    conn.execute("update foo set value = (select value from foo where id = 123)+1 where id = 123");  
You can manage database concurrency using isolation levels

Isolation Level     Dirty Read  Nonrepeatable Read  Phantom Read
READ UNCOMMITTED    Permitted   Permitted   Permitted
READ COMMITTED  --  Permitted   Permitted
REPEATABLE READ     --  --  Permitted
SERIALIZABLE

SERIALIZABLE-it provide highest level of concurrency

For details please  refer :

[http://www.oracle.com/technetwork/issue-archive/2005/05-nov/o65asktom-082389.html][1] 
SQL server将锁定正在使用的行(如果使用多行,将锁定所有行),并以原子方式执行操作


这也将更快/更高效,因为它只进行一次数据库调用,而不是两次。不过,这种更新实际上需要包装到存储过程中。

最简单的方法是将SQL包装到一个语句中,让SQL server处理它,我一时记不起确切的语法,但它可能类似于:

    conn.execute("update foo set value = (select value from foo where id = 123)+1 where id = 123");  
You can manage database concurrency using isolation levels

Isolation Level     Dirty Read  Nonrepeatable Read  Phantom Read
READ UNCOMMITTED    Permitted   Permitted   Permitted
READ COMMITTED  --  Permitted   Permitted
REPEATABLE READ     --  --  Permitted
SERIALIZABLE

SERIALIZABLE-it provide highest level of concurrency

For details please  refer :

[http://www.oracle.com/technetwork/issue-archive/2005/05-nov/o65asktom-082389.html][1] 
SQL server将锁定正在使用的行(如果使用多行,将锁定所有行),并以原子方式执行操作



这也将更快/更高效,因为它只进行一次数据库调用,而不是两次。不过,这种更新实际上需要包装到存储过程中。

这就是所谓的丢失更新问题。您可以使用专用锁。这将阻止其他事务读取锁定的数据。

这称为丢失更新问题。您可以使用专用锁。这将阻止其他事务读取锁定的数据。

这称为丢失更新问题。您可以使用专用锁。这将阻止其他事务读取锁定的数据。

这称为丢失更新问题。您可以使用专用锁。这将阻止其他事务读取锁定的数据。

我实际尝试执行的代码将使其变得难以处理-是否有任何方法锁定特定行?您需要使用SQL事务。如果设置正确并启动事务,然后访问事务中的行,则它将锁定该行,直到事务结束。不过,我还是建议在一个存储过程中完成整个过程。很抱歉,我没有完全理解-那么我的小示例不应该像现在这样工作吗?它只访问事务中的一行。是的,但这样读取不会锁定该行,您需要为事务设置隔离级别,否则仅从一行读取不会锁定该行。我已经检查了connection.getTransactionIsolation(),它为我返回了事务\u REPEATABLE\u READ。查看文档,看起来该级别应该可以防止脏读。但它并不能阻止幻影读取。这就是我在这里遇到的问题吗?我实际上试图执行的代码会使它变得很难处理-有没有办法锁定特定的行?您需要使用SQL事务。如果设置正确并启动事务,然后访问事务中的行,则它将锁定该行,直到事务结束。不过,我还是建议在一个存储过程中完成整个过程。很抱歉,我没有完全理解-那么我的小示例不应该像现在这样工作吗?它只访问事务中的一行。是的,但这样读取不会锁定该行,您需要为事务设置隔离级别,否则仅从一行读取不会锁定该行。我已经检查了connection.getTransactionIsolation(),它为我返回了事务\u REPEATABLE\u READ。查看文档,看起来该级别应该可以防止脏读。但它并不能阻止幻影读取。这就是我在这里遇到的问题吗?我实际上试图执行的代码会使它变得很难处理-有没有办法锁定特定的行?您需要使用SQL事务。如果设置正确并启动事务,然后访问事务中的行,则它将锁定该行,直到事务结束。不过,我还是建议在一个存储过程中完成整个过程。很抱歉,我没有完全理解-那么我的小示例不应该像现在这样工作吗?它只访问事务中的一行。是的,但这样读取不会锁定该行,您需要为事务设置隔离级别,否则仅从一行读取不会锁定该行。我已经检查了connection.getTransactionIsolation(),它为我返回了事务\u REPEATABLE\u READ。查看文档,看起来该级别应该可以防止脏读。但这并不能阻止潘
You can manage database concurrency using isolation levels

Isolation Level     Dirty Read  Nonrepeatable Read  Phantom Read
READ UNCOMMITTED    Permitted   Permitted   Permitted
READ COMMITTED  --  Permitted   Permitted
REPEATABLE READ     --  --  Permitted
SERIALIZABLE

SERIALIZABLE-it provide highest level of concurrency

For details please  refer :

[http://www.oracle.com/technetwork/issue-archive/2005/05-nov/o65asktom-082389.html][1]