数据访问层 - 静态列表对象和缓存

时间:2010-04-21 09:03:45

标签: asp.net-mvc caching data-access-layer

我使用.net MVC开发网站

我有一个数据访问层,它基本上由从我的数据库中的数据创建的静态列表对象组成。

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

public static List<PostCode> AllPostCodes = new List<PostCode>();
  1. 调用rebuild方法时,首先清除列表。

    ListPostCodes.AllPostCodes.Clear();

  2. 接下来它通过调用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;
            }
        }
    }
    
  3. 重建每1小时进行一次。这可以确保网站每隔1小时就会有一组新的缓存数据。

    我遇到的问题是偶尔如果在重建期间,服务器将被请求命中并抛出异常。例外是“索引超出了数组的范围。”这是由于清单何时被清除。

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

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

    我有2个问题......

    1. 如果我使用缓存而不是静态对象会有帮助吗?
    2. 我有什么方法可以说“在重建过程中,等待它完成,直到接受请求”
    3. 任何帮助都是最适合的;)

      truegilly

4 个答案:

答案 0 :(得分:1)

  

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

是的,通过构建到ASP.NET中的缓存功能

可以更轻松地完成您所做的一切
  

我有什么方法可以说“当   正在重建,等待它   完成直到接受请求“

常见模式如下:

  1. 您从数据层请求数据

  2. 如果Datlayer看到缓存中有数据,那么它会从缓存中提供数据 如果缓存中没有数据,则从数据库请求数据并将其放入缓存中。之后,它将提供给客户

  3. 要清除缓存时有规则(CacheDependency和Timeout)。

    最简单的解决方案是坚持这种模式:这样第一个请求就会触及数据库,其他请求会从缓存中获得。您可以通过实现SQLCacheDependency

    来触发刷新

答案 1 :(得分: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类,它在内部使用锁定来使列表对象本身是线程安全的。

答案 2 :(得分:0)

我同意Tom的意见,你必须做同步才能完成这项工作。在实际从数据库中收到新值之前,有一点可以改善性能:

// 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()时仍然有效。它还有一个优点,你可以使用只读列表,使同步更容易。

答案 3 :(得分:0)

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

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

2)采用上述方法,缺点是数据可能会陈旧1小时。因此,如果您始终需要大多数更新数据,请使用SQLCacheDependency(PUSH)。因此,每当使用select命令发生更改时,将使用更新的数据从数据库刷新缓存。