SQL Server 中的存储过程 INSERT INTO table1 VALUES A , B
值集 A 具有以下参数之一:(SELECT TOP 1 cashbalance - 1 FROM table1 WHERE userid = __ ORDER BYcreatedUTC, ID)
值集 B 具有以下参数之一:(SELECT TOP 1 cashbalance + 1 FROM table1 WHERE userid = __ ORDER BYcreatedUTC, ID)
当作为多个插入运行时,SELECT 语句仅运行一次,因此如果两个值集的 userid 相同,则 cashbalance 字段表示从第一个插入行中的 0 条记录 -1 和 1 开始(即不返回到 0)正如它应该的那样)在第二个插入的行中。此外,两行的createdUTC字段记录了完全相同的值。
当作为连续的单独 INSERT 语句运行时,cashbalance 字段可以正确计算,但createdUTC 字段有一个微小的间隙 - 但推断出对另一个插入/读取的关注。
显然与锁和/或序列化有关——我正在研究并将发布结果(尽管非常欢迎建议)。我也可以 SELECT SUM(table1.amounts) +/- 1 WHERE userid = __ (并注意 1 实际上是一个变量),但这并不能解决任何一个问题。此外,这个 sp 是四个 sp 进程(加上另一个调用 sp)的一步,这使得在哪里实现任何锁或事务变得更加复杂。
理想情况下,我尝试使用立即连续的 id 和相同的createdUTC 来实现复式记账(即每笔交易都有一行借记 A,另一行同时贷记 B 相同的金额)。
对于您提出的用例,您实际上可以只读取一次
cashbalance
,进行操作并将它们保存到局部变量,然后将它们用作过程调用的参数,如下所示:通过首先从表中读取一次,然后进行操作,您可以原子读取
cashbalance
对于所有操作来说都是恒定的值。这还可以提高查询的运行时间并减少正在读取的表的锁定时间。一切美好的事物。这仅取决于您的事务隔离级别以及您希望系统如何运行。默认情况下,在
READ COMMITTED
隔离级别下,编写者会阻止读取者(如您所知)。这个想法是,如果写入在读取发生之前开始,则正在发生更改,并且应该在读取获取值之前首先完成更改,这是正确的。如果您希望读取能够访问该行的先前版本,当该行当前被写入锁定时,您可以将隔离级别更改为
SNAPSHOT
RCSIREAD COMMITED SNAPSHOT ISOLATION
。那么读取就不会等待写入完成。以下是有关启用这些隔离级别的一些进一步信息。