Java sql read + write - 防止竞争条件?

时间:2014-01-18 18:17:03

标签: 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;
        conn.execute("update foo set value = " + value + " where id = 123");  

        conn.commit();
    }
    catch (SQLException ex) {
        conn.rollback(); 
    }
    finally {
        conn.close();
    }
} 

因此,如果线程执行大约相同的时间,则看起来read + write不会作为一个原子项执行。例如,如果起始值为零,我的日志显示如果两个线程几乎同时执行,则结束值可以是1而不是2。

我可以使用不同的锁定级别来防止这种情况吗?当然,如果有必要,我可以在java代码中进行同步,但我可能在这里缺少数据库级别为我们提供的一个重要功能。

由于

http://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html

3 个答案:

答案 0 :(得分:2)

最简单的方法是将SQL包装成一个语句并让SQL服务器处理它,我不记得手头的确切语法,但它会是这样的:

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

SQL服务器将锁定正在使用的行(如果使用多行将全部锁定它们)并以原子方式执行操作。

这也会更快/更高效,因为它只会使单个数据库调用而不是两个。这种更新实际上可以包含在存储过程中。

答案 1 :(得分:1)

这称为丢失更新问题。你可以使用独家锁。这将阻止其他交易读取锁定的数据。

答案 2 :(得分:0)

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]