我有两个线程调用一个方法,该方法在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
答案 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]