【发布时间】:2018-03-14 17:15:33
【问题描述】:
我正在尝试使用 JDBC 实现一些业务逻辑,但我不明白我得到的结果。
我有 n 个线程,每个线程执行以下伪代码:
//before threads execution
m <- exec("select x from t where id = 1")
// inside thread
conn.setAutocommit(false);
//do some stuff on the db
v <- exec("select x from t where id = 1")
exec("update t set x = {v}+1 where id=1")
conn.commit();
// after threads execution
exec("select x from t where id = 1") //result should be m+n, but it isn't
当我运行此代码时,t 表的 x 列不会像我预期的那样增加 n。当然所有线程之间存在并发问题。
如果我用以下代码替换该代码,则它可以正常工作:
//before threads execution
m <- exec("select x from t where id = 1")
// inside thread
conn.setAutocommit(false);
//do some stuff on the db
exec("update t set x = x+1 where id=1")
conn.commit();
// after thread execution
exec("select x from t where id = 1") //result is be m+n
但由于第一个代码在事务中,不应该等同于第二个版本吗?
我还尝试将隔离级别限制为 SERIALIZABLE,但我始终观察到相同的行为。
编辑:我用每个线程的不同连接重写了我的代码,结果是相同的。
【问题讨论】:
-
您面临的问题是什么?
-
'我有 n 个线程(共享一个连接)'并且以某种随机顺序触发
connection.commit()?!这行不通。获取一个连接池,使用适当的事务划分并使用某种形式的 - 也许是乐观的 - 锁定。 -
那是什么意思'共享同一个连接'呢?
-
是的,这是个坏主意。如果您现在有单独的连接,则隔离级别的设置可能会起作用。还是
SERIALIZABLE吗? -
您的
exec()是做什么的?它如何替换{v}+1部分?但其他事务可以轻松更新您事务的select和update语句之间的表。
标签: java postgresql jdbc concurrency transactions