2010-04-21 138 views
2

我正在发民使用.NET MVC数据访问层 - 静态列表对象和缓存

我有一个基本组成是从我的数据数据库中创建静态列表对象的数据访问层的站点。

重建此数据的方法首先清除所有列表对象。一旦它们是空的,然后添加数据。这是我使用的一个列表的例子。它是一种生成所有英国邮政编码的方法。大约有50的方法与此类似在我的应用程序返回的各种信息,如城镇,地区,会员,电子邮件等

public static List<PostCode> AllPostCodes = new List<PostCode>(); 
  1. 当重建方法被调用它首先清除列表。

    ListPostCodes.AllPostCodes.Clear();

  2. 下将其重新bulilds中的数据,通过调用GetAllPostCodes()方法

    /// <summary> 
    /// static method that returns all the UK postcodes 
    /// </summary> 
    public static void GetAllPostCodes() 
    { 
        using (fab_dataContextDataContext db = new fab_dataContextDataContext()) 
        { 
         IQueryable AllPostcodeData = from data in db.PostCodeTables select data; 
    
         IDbCommand cmd = db.GetCommand(AllPostcodeData); 
         SqlDataAdapter adapter = new SqlDataAdapter(); 
         adapter.SelectCommand = (SqlCommand)cmd; 
         DataSet dataSet = new DataSet(); 
    
         cmd.Connection.Open(); 
         adapter.FillSchema(dataSet, SchemaType.Source); 
         adapter.Fill(dataSet); 
         cmd.Connection.Close(); 
    
         // crete the objects 
         foreach (DataRow row in dataSet.Tables[0].Rows) 
         { 
          PostCode postcode = new PostCode(); 
          postcode.ID = Convert.ToInt32(row["PostcodeID"]); 
          postcode.Outcode = row["OutCode"].ToString(); 
          postcode.Latitude = Convert.ToDouble(row["Latitude"]); 
          postcode.Longitude = Convert.ToDouble(row["Longitude"]); 
          postcode.TownID = Convert.ToInt32(row["TownID"]); 
    
          AllPostCodes.Add(postcode); 
          postcode = null; 
         } 
        } 
    } 
    

重建时每隔1小时。这确保了网站每1小时将有一组新的缓存数据。

问题得到的是,偶尔如果在重建过程中,服务器将被一个请求命中并抛出一个异常。例外是“索引超出了数组的范围”。这是由于列表被清除时。

ListPostCodes.AllPostCodes.Clear(); - // throws exception - although its not always in regard to this list. 

一旦抛出此异常,应用程序就会死亡,所有用户都将受到影响。我必须重新启动服务器才能修复它。

我有2个问题...

  1. 如果我使用缓存,而不是静态的物体会帮助呢?
  2. 有什么办法,我可以说“而重建正在发生,等待它完成,直到接受请求”

任何帮助是最appricaiated;)

truegilly

+0

最正确的解决方案是避免静态方法,这是不好的。我的意思是,总是不好。即使你认为没问题,也要三思,因为这很糟糕。如果您使用它们,请记住Web应用程序请求可能会在单独的线程上并发执行。然后,了解静态数据和线程,并再次决定是否需要它们。 – queen3 2010-04-21 09:30:06

回答

1

1如果我利用缓存而不是 静态对象会有帮助吗?

是的,所有的事情你更容易通过缓存功能,是建设成ASP.NET

做有什么办法,我可以说“,而 重建正在发生,等待它 完成,直到接受请求”

常见的模式是这样的:

  1. 您从数据层

  2. 请求数据如果Datlayer看到有缓存中的数据,然后它会投放缓存 数据如果没有数据在缓存中的数据从数据库请求并放入缓存。之后,它被送达客户端

当缓存被清除时,有规则(CacheDependency和Timeout)。

最简单的解决方案就是坚持这种模式:这样第一个请求会碰到数据库,其他请求将从缓存中获取。您通过实施SQLCacheDependency触发刷新

+0

即时通讯将实施您的sugesstion,一旦其就位,如果我遇到任何更多的问题,看看同步和线程评论 谢谢 – JGilmartin 2010-04-21 12:58:50

0

你必须确保您的列表不被一个线程修改,而其他线程正在尝试使用它。即使您使用ASP.NET缓存,这也会成为问题,因为集合不是线程安全的。一种可以做到这一点的方法是使用SynchronizedCollection而不是List。然后,请务必使用如下代码,当你访问集合:

lock (synchronizedCollection.SyncRoot) { 
    synchronizedCollection.Clear(); 
    etc... 
} 

您还将有当你读集合使用锁定。如果你正在列举它,你应该先做一个副本,因为你不想长时间锁定。例如:

List<whatever> tempCollection; 
lock (synchrnonizedCollection.SyncRoot) { 
    tempCollection = new List<whatever>(synchronizedCollection); 
} 
//use temp collection to access cached data 

另一种选择是创建一个ThreadSafeList类,该类使用内部锁定来使列表对象本身是线程安全的。

0

我同意汤姆,你将不得不做同步,使这项工作。这将提高性能的一件事是不清除列表,直到你从数据库中实际收到的新值:

// Modify your function to return a new list instead of filling the existing one. 
public static List<PostCode> GetAllPostCodes() 
{ 
    List<PostCode> temp = new List<PostCode>(); 
    ... 
    return temp; 
} 

当你重建数据:

List<PostCode> temp = GetAllPostCodes(); 
AllPostCodes = temp; 

这可以确保您的缓存列表仍然有效,而GetAllPostCodes()正在执行。它还具有可以使用只读列表的优点,这使得同步变得更容易一些。

0

在你的情况下,你需要每隔1小时刷新一次数据。

1)IT应该使用绝对过期设置为1小时的缓存,因此每隔1小时过期一次。在使用它之前检查缓存,通过执行NULL检查。如果它的NULL从DB获取数据并填充缓存。

2)使用上述方法的缺点是数据可能陈旧1小时。因此,如果您始终想要最新的数据,请使用SQLCacheDependency(PUSH)。因此,只要使用选择命令时发生变化,就会使用更新的数据从数据库刷新缓存。