如何使用C#和SQL在高事务应用程序中每5分钟记录一次对数据库的更改?

Yak*_*MIK 6 c# sql asp.net logging caching

想象一下这种情况:你有一个WCF网络服务,每天可以达到一百万次.每个匹配包含一个"帐户ID"标识符.WCF服务托管在分布式ASP.NET群集中,并且您没有对服务器的远程桌面访问权限.

您的目标是将每个帐户ID的"每小时点击次数"保存到SQL数据库中.结果应如下所示:

[Time], [AccountID], [NumberOfHits]
1 PM, Account ID (Bob), 10 hits
2 PM, Account ID (Bob), 10 hits
1 PM, Account ID (Jane), 5 hits
Run Code Online (Sandbox Code Playgroud)

问题是:如果不在每次点击时连接到SQL服务器数据库,如何才能做到这一点?

这是我想到的一个解决方案:将临时结果存储在System.Web.Cache对象中,监听其过期,并在Cache Expiration上,在Cache过期时将所有累积数据写入数据库.

有关更好方法的任何想法?

Rem*_*anu 3

事实上,延迟更新是关键,并且您的本地缓存方法走在正确的道路上。只要您不需要在每次访问时显示上次更新计数,解决方案很简单:更新 account_id->count 的本地缓存并定期扫描此缓存,将计数替换为 0 并添加数据库中总数的计数。如果ASP.Net 进程丢失,并且显示的点击计数不准确(ASP 场中的节点 1 返回其纬度计数,节点 2 返回其自己的本地计数,与节点 1 不同),则可能会丢失一些访问计数

如果您必须准确显示每个返回结果的计数(无论这是页面返回还是服务返回,都无关紧要),那么它很快就会变得很麻烦。像 Memcache 这样的集中式缓存可以帮助创建解决方案,但它并不是微不足道的。

这是我保留本地缓存的方法:

class HitCountCache
{
   class Counter 
   {
       public unsigned int count {get;set}
       public accountid {get;set}
   };

   private Dictionary<accountType, Counter> _counts = new Dictionary<...>();
   private Object _lock= new Object();

   // invoke this on every call
   //
   void IncrementAccountId (accountId)
   {
      Counter count;
      lock(_lock) 
      {
         if (_counts.TryGetValue (accountId, out count))
         {
            ++count.count;
         }
         else
         {
            _counts.Add (accountId, 
                new Counter {accountId = accountId; count=0});
         }
      }
   } 

   // Schedule this to be invoked every X minutes
   //
   void Save (SqlConnection conn)
   {
      Counter[]  counts;

      // Snap the counts, under lock
      //
      lock(_lock)
      {
          counts = _counts.ToArray();
          _counts.Clear();
      }

      // Lock is released, can do DB work
      //
      foreach(Counter c in counts)
      {
          SqlCommand cmd = new SqlCommand(
                 @"Update table set count+=@count where accountId=@accountId", 
                 conn);
          cmd.Parameters.AddWithValue("@count", c.count);
          cmd.Parameters.AddWithValue("@accountId", accountId);
          cmd.ExecuteNoQuery();
      }
   } 
}
Run Code Online (Sandbox Code Playgroud)

这是一个骨架,可以改进,如果需要的话还可以返回当前的总计数,至少是本地节点已知的总计数。