我们正在使用NHibernate更新用户余额的帐户表。阻碍我们的一个测试案例是:
var s = NHibernateHelper.OpenSession();
var q = s.CreateQuery("Update Account set Balance=? where UserId=? and Version=?");
var acc = s.Load(1);
ITransaction tx = null;
for (int j = 0; j < NUM_UPDATES; j++)
{
int rowcount = 0;
var tx = s.BeginTransaction();
do
{
s.Refresh(acc);
q.SetDouble(0, acc.Balance + _amount).SetInt32(1, 1).SetBinary(2, acc.Version);
rowcount = q.ExecuteUpdate();
} while (rowcount <= 0);
tx.Commit();
}
此代码同时在单个线程和多个线程中执行(因此版本控制)。它正确执行,但是 - 版本号增加了一个数字,该数字比实际更新计数(NUM_UPDATES)增加了一些值。
e.g。如果我们进行16次更新,版本号将增加16或17.如果我们进行1000次更新,版本号将增加1004。
如果16个线程运行相同的代码(在4核机器上),每个代码有1000个更新,那么我们显然会进行大量重试,并且版本增加16064(1004 * 16)。
知道是什么导致了这个吗?是否有引起警报的原因?
答案 0 :(得分:4)
如果版本列的类型为timestamp或rowversion,则使用全局计数器更新它。只要插入或更新包含rowversion列的任何表中的任何行,该全局计数器就会递增。 因此,这不是一个值得关注的问题。它仅反映数据库中的其他活动。
答案 1 :(得分:0)
Read here 有关SQL Server中rowvwersion (timestamp)
的更多信息。要了解的事情:
答案 2 :(得分:0)
由于您正在构建自己的查询,因此可以在UPDATE中以原子方式递增列:
UPDATE Account SET Balance = Balance + @amount WHERE UserId = @uid
这也将节省创建和提交单独事务的开销。