我使用.net MVC开发网站
我有一个数据访问层,它基本上由从我的数据库中的数据创建的静态列表对象组成。
重建此数据的方法首先清除所有列表对象。一旦它们为空,然后添加数据。这是我正在使用的一个列表的示例。它是一种生成所有英国邮政编码的方法。在我的应用程序中有大约50种与此类似的方法可以返回各种信息,例如城镇,地区,成员,电子邮件等。
public static List<PostCode> AllPostCodes = new List<PostCode>();
调用rebuild方法时,首先清除列表。
ListPostCodes.AllPostCodes.Clear();
接下来它通过调用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个问题......
任何帮助都是最适合的;)
truegilly
答案 0 :(得分:1)
1如果我使用缓存而不是 静态对象会有帮助吗?
是的,通过构建到ASP.NET中的缓存功能
可以更轻松地完成您所做的一切我有什么方法可以说“当 正在重建,等待它 完成直到接受请求“
常见模式如下:
您从数据层请求数据
如果Datlayer看到缓存中有数据,那么它会从缓存中提供数据 如果缓存中没有数据,则从数据库请求数据并将其放入缓存中。之后,它将提供给客户
要清除缓存时有规则(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命令发生更改时,将使用更新的数据从数据库刷新缓存。