结束语是不够的,在某些情况下,无论您定义的隔离级别的事务中的代码。
比方说你有这些步骤和2个并发线程:
1) open a transaction
2) fetch the data (SELECT creds FROM credits WHERE userid = 1;)
3) do your work (credits + amount)
4) update the data (UPDATE credits SET creds = ? WHERE userid = 1;)
5) commit
而这一次行:
Time = 0; creds = 100
Time = 1; ThreadA executes (1) and creates Txn1
Time = 2; ThreadB executes (1) and creates Txn2
Time = 3; ThreadA executes (2) and fetches 100
Time = 4; ThreadB executes (2) and fetches 100
Time = 5; ThreadA executes (3) and adds 100 + 50
Time = 6; ThreadB executes (3) and adds 100 + 50
Time = 7; ThreadA executes (4) and updates creds to 150
Time = 8; ThreadB tries to executes (4) but in the best scenario the transaction
(depending of isolation level) won't allow it and you get an error
的事务可以防止您覆盖一个错误值vim的信任状值,但它不是够了,因为我不想失败任何错误。
我宁愿选择一个永远不会失败的较慢进程,我在获取数据(第2步)时解决了“数据库行锁定”问题,以防止其他线程在完成之前读取同一行用它。
有办法少在SQL Server做,这就是其中之一:
SELECT creds FROM credits WITH (UPDLOCK) WHERE userid = 1;
如果我创建与这个改进之前的时间线,你得到的东西是这样的:
Time = 0; creds = 100
Time = 1; ThreadA executes (1) and creates Txn1
Time = 2; ThreadB executes (1) and creates Txn2
Time = 3; ThreadA executes (2) with lock and fetches 100
Time = 4; ThreadB tries executes (2) but the row is locked and
it's has to wait...
Time = 5; ThreadA executes (3) and adds 100 + 50
Time = 6; ThreadA executes (4) and updates creds to 150
Time = 7; ThreadA executes (5) and commits the Txn1
Time = 8; ThreadB was waiting up to this point and now is able to execute (2)
with lock and fetches 150
Time = 9; ThreadB executes (3) and adds 150 + 50
Time = 10; ThreadB executes (4) and updates creds to 200
Time = 11; ThreadB executes (5) and commits the Txn2
如果您担心违反列上的约束条件,请在数据库中定义CONSTRAINTS。 – jva 2009-07-29 10:36:38