【问题标题】:prevent same object return in the same time in db4o防止在 db4o 中同时返回相同的对象
【发布时间】:2011-03-28 19:57:53
【问题描述】:

我在一个 asp.net Web 应用程序中使用 db4o,正如您所知,当 db4o 返回一个它们未排序的对象列表时。

在我的网站中,我运行查询并获取结果中的最后一个对象并对其进行处理(一些处理,然后更新其中一个字段)。

我的问题是,如果我在处理该对象时,如果另一个用户到达并再次运行该查询,相同的对象返回给他,并且两个用户都得到相同的对象。

我不想让这种情况发生。我怎样才能防止它发生?

【问题讨论】:

    标签: db4o


    【解决方案1】:

    不确定 DB4O 是否提供了开箱即用的类似功能,但可以自己实现某种悲观锁,即不会返回相同的对象,或者以只读模式返回。您需要维护正在编辑的对象列表,并在每次返回对象时检查此列表。但是随后会出现诸如用户离开和对象陷入“编辑模式”等问题。您通常需要某种涉及超时机制的服务来处理这些问题。它可能会变得复杂。

    或者乐观地去做,例如让两个用户都编辑它,但只保存第一个用户的更改,并在第二个用户尝试保存它时发出警告。通常使用时间戳完成。

    编辑

    为了提供一个具体的例子,这个 C# 代码提供了一种“锁定”对象的基本方法,因此它不会每次都被恢复。但在现实生活中它会更复杂。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace ListTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                DataAccess dataAccess = new DataAccess();
    
                // get objects from database
                List<MyThing> things = dataAccess.GetThings();
                MyThing thingToWorkOn = things[things.Count-1];
                printThingList(things);
    
                // lock the object to work on
                dataAccess.LockThing(thingToWorkOn);
    
                // someone else gets the list - doesn't include thing being edited
                List<MyThing> moreThings = dataAccess.GetThings();
                printThingList(moreThings);
    
                // edit the object
                thingToWorkOn.Name = "Harrold";
                thingToWorkOn.Name = "Harry";
    
                // save the object and unlock it
                dataAccess.Save(thingToWorkOn);
                dataAccess.UnlockThing(thingToWorkOn);
    
                // now when someone else gets the list, includes all objects
                List<MyThing> evenMoreThings = dataAccess.GetThings();
                printThingList(evenMoreThings);
            }
    
            static void printThingList(List<MyThing> things)
            {
                Console.WriteLine("* Things *");
                things.ForEach(x => Console.WriteLine(x.Name));
                Console.WriteLine();
            }
        }
    
        // The objects you're working with.  Could just use 'object' or some interface.
        class MyThing : IEquatable<MyThing>
        {
            public string Name { get; set; }
    
            public bool Equals(MyThing other)
            {
                return other.Name == this.Name;
            }
        }
    
        // Class to get objects from database.
        class DataAccess
        {
            // simple list to store 'locked' objects
            private static List<MyThing> lockedThings = new List<MyThing>();
    
            // Get all objects except the locked ones
            public List<MyThing> GetThings()
            {
                List<MyThing> thingsFromDatabase = LoadThingsFromDatabase();
    
                var nonLockedThings = (from thing in thingsFromDatabase
                                       where !lockedThings.Contains(thing)
                                       select thing
                                        ).ToList<MyThing>();
    
                return nonLockedThings;
            }
    
            // lock an object so it can't be seen by anyone else
            public void LockThing(MyThing thingToLock)
            {
                lockedThings.Add(thingToLock);
            }
    
            // unlock an object
            public void UnlockThing(MyThing thingToLock)
            {
                lockedThings.Remove(thingToLock);
            }
    
            public void Save(MyThing thing)
            {
                // save to database
            }
    
            // dummy method to give us some objects
            private List<MyThing> LoadThingsFromDatabase()
            {
                return new List<MyThing>() {
                    new MyThing(){ Name="Tom" },
                    new MyThing(){ Name="Dick" },
                    new MyThing(){ Name="Harry" }
                };
            }
        }
    }
    

    【讨论】:

    • 这不是 DB4O 的事情,这是你必须自己做的事情。这解释了一点:agiledata.org/essays/concurrencyControl.html#PessimisticLocking。那篇文章是关于数据库的,但无论如何都适用相同的原则。
    • 基本上当第一个用户开始处理一个对象时,你把它放在一个列表中,也许(在 C# 中)'List LockedObjects'。当其他人想要使用一个对象时,您检查它是否在该列表中 - 如果是,则不允许他们使用它,或者他们只能读取它而不能更新它。当第一个人完成编辑后,该对象将从该列表中删除。
    • 谢谢格兰特,我们在数据库上有什么东西可以做这个 List 工作吗? DBMS 中是否有任何功能可以做到这一点?像锁或类似的东西
    • 我所说的事情,你必须自己做。您使用什么语言?
    • 查看已编辑答案中的代码示例,这可能会给您一些想法
    【解决方案2】:

    您可以使用 db4o 中内置的带外消息支持来实现基本锁定系统。上面的 Grant 列表可以在 db4o 服务器上实现。客户端向服务器发送消息“我想编辑对象 x”,服务器尝试将对象放入其列表中。如果成功,它将回复“是,继续”消息,否则可以回复“否,稍后再试”。当客户端完成编辑后,它会向服务器发送一条消息说“我已经完成了对象 x”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-17
      相关资源
      最近更新 更多