NHibernate和新创建的记录锁定

NHibernate和新创建的记录锁定,nhibernate,locking,Nhibernate,Locking,我有两张桌子。 钱包营业额和钱包余额 钱包周转是以特定货币和特定客户对钱包进行的贷记和借记操作 钱包余额包含每个客户和货币的最多一条记录,其中包含客户和货币的余额。余额是钱包周转产生的贷记和借记的总和。 我想这样做,当我将营业额添加到营业额表中时,我需要通过添加当前营业额来重新计算余额表。如果当前营业额的货币和客户记录还不存在,我想创建一个新的记录 问题是,我应该如何防止应用程序在余额表中为同一客户机和货币创建多个余额记录 想象一下,我正在为id=1、币种=USD的客户添加营业额。 该记录尚不存

我有两张桌子。 钱包营业额和钱包余额

钱包周转是以特定货币和特定客户对钱包进行的贷记和借记操作

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

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

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

我应该怎么做才能实现这样的行为:当我第一次由用户A创建钱包余额记录时,它现在还没有保存到数据库中,应用程序的第二个用户B必须等到第一个用户提交其记录,而不是读取当前余额(其中包含用户A更新的余额)并继续保持正确的平衡值

这样的事情还能实现吗?我应该如何让nhibernate知道,客户端id=1、币种=USD的余额记录已经有一些用户创建了,因此,当其他用户在表中查找该组合时,该记录已经创建,用户应该等待用户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.Upgrade)

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

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

多谢各位

彼得

编辑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;
        }
`


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

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

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

  • 您可以捕获唯一冲突并让该进程重试。第二 go它将找到另一个事务提交的记录

  • 您可以使用可序列化事务隔离级别。这是最安全的隔离 水平。如果我的想法正确,它应该确保当任何进程试图 读取一条现有记录,它将要么不获取任何记录,要么获取现有记录,或者 任何其他打开的事务都已查找它将阻止的同一记录 并等待另一个事务完成


我发现如何使用lock语句处理平衡/周转模式。所以也许我也可以使用lock语句。我关心的是nhibernate文档中的这句话:nhibernate将始终使用数据库的锁定机制,从不在内存中锁定对象!如果我在内存中创建新的WalletBalance记录,这句话也是真的吗?我最终得到了如下结果: