2010-08-12 43 views
1

我在一个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" } 
      }; 
     } 
    } 
} 
+0

什么是悲观锁? – iBoy 2010-08-12 10:18:39

+1

这不是一个DB4O的事情,这是你必须对自己。这解释了一点:http://www.agiledata.org/essays/concurrencyControl.html#PessimisticLocking。那篇文章是关于数据库的,但无论如何也适用同样的原则。 – 2010-08-12 10:48:57

+0

基本上,当第一个用户开始在一个对象上工作时,可以将它放在一个列表中,或许(在C#中)'列表 LockedObjects'。当其他人想要使用某个对象时,请检查它是否在该列表中 - 如果是,则不允许使用该对象,或者只能读取而不更新它。当第一个人完成编辑时,该对象将从该列表中删除。 – 2010-08-12 10:51:13

0

您可以使用db4o内置的带外消息传递支持来实现基本的锁定系统。上面的Grant的列表可以在db4o服务器上实现。客户端发送消息给服务器'我想编辑对象x',服务器试图把对象放在列表中。如果成功,它会以'Yes,Go ahead'消息回复,否则它可以回答'不,稍后再试'。当客户端完成编辑时,它会向服务器发送一条消息,说'我已经完成了对象x'。

相关问题