0

我们将 .Net 与 Nhibernate 和 Castle 用于 IOC(用于所有服务和存储库)。最近的部署开始发生一些奇怪的事情,我无法追踪问题。

我们在存储库中有以下代码块,在创建 ObjA 后从服务调用:

    public void Save(IList<ObjA> listA, IList<ObjB> listB, ObjC c, Objd d) {
        using (var session = GetSession()) {
            using (var tx = session.BeginTransaction()) {
                try {
                    session.Save(c);
                    foreach (var a in listA) {
                        session.Update(a);
                    }
                    foreach (var b in listB) {
                        // unrelated field updates here
                        session.Save(b);
                    }
                    session.Update(d);
                    if (!tx.WasCommitted) {
                        tx.Commit();
                    }
                } catch (Exception) {
                    if (tx != null) {
                        tx.Rollback();
                    }
                    throw;
                }
            }
        }
    }

此代码称为在 listA 中传递 1 个 ObjA,在 listB 中传递 1 个 ObjB,再加上 ObjC 和 ObjD。

我们发现随机(大约有一半的时间)我们得到了重复的 ObjB 和 ObjC 记录(这里唯一被创建而不是更新的对象)。由于 ObjC 有一个 datetime 字段,我可以跟踪记录的创建时间,并且有时会在大约 12-18 小时内创建 5-100 条重复记录。这是在数据库中创建 ObjB 和 ObjC 记录的唯一代码。

我以前从未见过这样的事情,似乎有什么东西卡在了内存中并间歇性地调用这个函数(或 Nhibernate 调用)。我在其中一个似乎存在此问题的服务器上重新启动了 IIS,问题停止了,但第二天又在另一台服务器上启动。

有没有人对可能导致这种情况的原因有任何想法?Castle 或 Nhibernate 的配置中是否存在可能导致这些调用卡住并重复 12-18 小时(超过 100 次?)?

任何帮助表示赞赏:)

Service(){

    _saveLater = null;

    CalledByWS(){
        CreateObjA();
        CreateOtherObjs();  

    }   

    CreateObjA(){
        //Do a lot of stuff here

        var a = new ObjA{ };
        listToBeSaved.Add(a, SaveOrUpdate.Save);

        //Update other objects & add to the list

        if(xyz){
            _saveLater.ObjA = a
            _saveLater.ObjB = GetObjB(a);
            _saveLater.ObjC = GetObjC(a);   
        }

        _repo.SaveOrUpdate(listToBeSaved);
    }

    CreateOtherObjs(){
        if(_saveLater == null) return;

        Save(new List<ObjA> {_saveLater.ObjA}, new List<ObjB> {_saveLater.ObjB},
                _saveLater.Objc, _saveLater.ObjD);  //The original function posted
    }
}

Repo(){

  SaveOrUpdate(Dictionary<IEntity, SaveOrUpdate> objs){
    using (var session = GetSession()){
      using (var tx = session.BeginTransaction()) {
        try {
            foreach (var o in objs) {
                if (o.Key == null) continue;
                if (o.Value == SaveOrUpdate.Update)
                    session.Update(o.Key);
                else
                    session.Save(o.Key);
            }
            if (!tx.WasCommitted) {
                tx.Commit();
            }
        } catch (Exception) {
            if (tx != null) {
                tx.Rollback();
            }
            throw;
        }
      }
        }
    }


}
4

2 回答 2

0

艾米,如果你看看发生的事情的最终结果,它会告诉你发生了什么。您传递的 ObjA 应该为每个唯一的 ObjA “创建”多个 ObjB 记录和 1 个 ObjC 记录。我猜您正在将您的 ObjA 与此函数范围之外的 ObjB 和 ObjC 相关联,然后依靠保存来保持该更改。这样想,最终会有很多不同的 ObjB 记录,外键指向同一个 ObjA 记录,而且大部分都不正确。 出于某种原因,您的生产代码将 ObjA 与传递给此函数的 ObjB 和 ObjC 的相同 ID 相关联。关系代码甚至可以在设置传递给函数的 ObjA 之前将它们关联起来。在调用保存之前检查您对 ObjA 的更新并记录关联代码。您可能需要考虑调用该服务的第三方供应商之一可能会多次向您发送相同的数据。

于 2012-04-25T18:50:41.940 回答
0

在我去寻找一个更复杂的问题之前,比如电话卡在内存中或者类似的东西,我会把钱花在保存功能本身被多次触发上。请注意,您注意到的唯一重复项是正在保存的对象。更新很可能也运行了多次,并且没有明显的副作用。

是否从 Web 应用程序调用此方法?提交按钮是否被双击?您可以通过添加日志记录机制并在调用 Save 方法以及调用它的参数时记录日志来测试这个理论。

于 2012-04-23T20:55:00.617 回答