NHibernate和新创建的记录锁定



我有两个表。钱包周转和钱包余额。

钱包周转是针对特定货币和特定客户的钱包的信用和借记操作。

钱包余额包含每个客户和货币最多一条记录,其中包含客户和货币的余额。余额是钱包周转产生的贷项和借项的总和。我希望应用程序的行为方式是,当我将营业额添加到营业额表中时,我需要通过添加当前营业额来重新计算余额表。如果当前营业额的货币和客户记录还不存在,我想创建一个新的。

问题是,我应该如何防止应用程序在余额表中为同一客户和货币创建多个余额记录。

想象一下,我为id=1和currency=USD的客户添加营业额的情况。该记录还不存在,因此应该创建它。但是,当应用程序的两个并发用户A和B同时添加客户端1的营业额和货币美元时,会发生什么?

我应该做些什么来实现这样的行为,即当我第一次由用户A创建钱包余额记录时,它现在还没有保存到数据库中,应用程序的第二个用户B将不得不等到第一个用户提交其记录,然后读取当前余额(其中包含用户A更新的余额)并继续使用正确的余额值?

这样的事情能实现吗?我应该如何让nhibernate知道,客户端id=1,货币=美元的余额记录已经有一些用户创建了,所以,当其他用户在表中寻找这个组合时,这个记录已经创建,用户应该等到用户A提交它?

GetOrCreateBalance代码:

public ClientWalletBalance GetOrCreateWalletBalance(int clientId, int currency)
{
var clientObj = ClientService.GetClient(clientId);
var res = clientObj.WalletBalances.FirstOrDefault(x => x.Currency.Id == currency);
if (res == null)
{
res = new ClientWalletBalance()
{
Client = clientObj,
Currency = ClientService.GetCurrency(currency),
};
};
clientObj.WalletBalances.Add(res);
return res;
}

我已经知道,这可以通过实现

session.Lock(对象,LockMode.Update);

我只是不清楚,如果我锁定了新创建的对象,它还没有保存到DB中,所以它没有关联的id,nhibernate怎么会知道客户端1和货币USD的组合已经创建,是其他用户的"内存">

请问这种箱子的标准配方是什么?

非常感谢

Peter

编辑1:到目前为止,我的结局是这样的:呼叫代码:

using (ISession session = NHibernateConfiguration.ReturnOpenedSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
var cwb = Service.OrderAndPaymentService.GetOrCreateWalletBalance(clientId, currency, delay);
response.Error = cwb.Balance.ToString();
transaction.Commit();
}
}

`

调用代码:`

public ClientWalletBalance GetOrCreateWalletBalance(int clientId, int currency, int delay = 0)
{
var clientObj = ClientService.GetClient(clientId);
var res = clientObj.WalletBalances.FirstOrDefault(x => x.Currency.Id == currency);
if (res != null)
{
NHibernateConfiguration.GetCurrentSession().Lock(res, LockMode.Upgrade);
}
else
{
res = new ClientWalletBalance()
{
Client = clientObj,
Currency = ClientService.GetCurrency(currency),
Balance = delay,
};
clientObj.WalletBalances.Add(SaveClientWalletBalance(res));
NHibernateConfiguration.GetCurrentSession().Lock(res, LockMode.Upgrade);
}
System.Threading.Thread.Sleep(delay * 1000);
return res;
}

`

但两个不同的网络用户第一次调用相同的客户端Id和货币组合的可能性仍然存在问题,在这种情况下,将为相同的客户端和货币创建两个记录。我不能使用锁(对象)语法,因为我们使用的是web农场,它有多个不共享静态变量的应用服务器。

如果希望对象在数据库中的某些属性上是唯一的,则应通过在数据库中定义适当的unique约束来确保这一点。然后它将确保不会出现重复。

在下一步中,您需要考虑如果两个进程因为同时运行而试图添加重复记录,会发生什么:

  • 您可以捕获UNIQUE冲突,然后重试该进程。秒go将查找由另一个事务提交的记录。

  • 您可以使用SERIALIZABLE事务隔离级别。这是最安全的隔离数量如果我的想法是正确的,它应该确保当任何过程试图读取一个现有记录,它要么没有得到记录,要么得到现有记录,或者如果任何其他打开的事务都已经在查找它将阻止的相同记录并且等待直到另一个事务已经完成。

最新更新