阅读783 返回首页    go 阿里云 go 技术社区[云栖]


Enterprise Library深入解析与灵活应用(2): 通过SqlDependency实现Cache和Database的同步

  • AbsoluteTime:为cache item设置一个cache item的绝对过期时间。
  • ExtendedFormatTime:通过一个表达式实现这样的过期策略:每分钟过期(*****:5个*分别代表minute、hour、date、month、year);每个小时的第5分钟过期(5****);每个月的2号零点零分过期(0 0 2 * *)。
  • FileDependency:将cache item和一个file进行绑定,通过检测file的最后更新时间确定file自cache item被添加以来是否进行过更新。如果file已经更新则cache item过期。
  • NeverExpired:永不过期。
  • SlidingTime:一个滑动的时间,cache item的每次获取都将生命周期延长到设定的时间端,当cache item最后一次获取的时间算起,超出设定的时间,则cache item过期。

   1: public interface ICacheItemExpiration
   2: {
   3:     // Methods
   4:     bool HasExpired();
   5:     void Initialize(CacheItem owningCacheItem);
   6:     void Notify();
   7: } 

   1: namespace Artech.SqlDependencyCaching
   2: {
   3:     public class SqlDependencyExpiration : ICacheItemExpiration
   4:     {
   5:         private static readonly CommandType DefaultComamndType = CommandType.StoredProcedure; 
   6:  
   7:         public event EventHandler Expired; 
   8:  
   9:         public bool HasChanged
  10:         { get; set; } 
  11:  
  12:         public string ConnectionName
  13:         { get; set; } 
  14:  
  15:         public SqlDependencyExpiration(string commandText, IDictionary<string, object> parameters) :
  16:             this(commandText, DefaultComamndType, string.Empty, parameters)
  17:         { } 
  18:  
  19:         public SqlDependencyExpiration(string commandText, string connectionStringName, IDictionary<string, object> parameters) :
  20:             this(commandText, DefaultComamndType, connectionStringName, parameters)
  21:         { } 
  22:  
  23:         public SqlDependencyExpiration(string commandText, CommandType commandType, IDictionary<string, object> parameters) :
  24:             this(commandText, commandType, string.Empty, parameters)
  25:         { } 
  26:  
  27:         public SqlDependencyExpiration(string commandText, CommandType commandType, string connectionStringName, IDictionary<string, object> parameters)
  28:         {
  29:             if (string.IsNullOrEmpty(connectionStringName))
  30:             {
  31:                 this.ConnectionName = DatabaseSettings.GetDatabaseSettings(ConfigurationSourceFactory.Create()).DefaultDatabase;
  32:             }
  33:             else
  34:             {
  35:                 this.ConnectionName = connectionStringName;
  36:             } 
  37:  
  38:             SqlDependency.Start(ConfigurationManager.ConnectionStrings[this.ConnectionName].ConnectionString);
  39:             using (SqlConnection sqlConnection = DatabaseFactory.CreateDatabase(this.ConnectionName).CreateConnection() as SqlConnection)
  40:             {
  41:                 SqlCommand command = new SqlCommand(commandText, sqlConnection);
  42:                 command.CommandType = commandType;
  43:                 if (parameters != null)
  44:                 {
  45:                     this.AddParameters(command, parameters);
  46:                 }
  47:              SqlDependency dependency = new SqlDependency(command);
  48:                 dependency.OnChange += delegate
  49:                 {
  50:                     this.HasChanged = true;
  51:                     if (this.Expired != null)
  52:                     {
  53:                         this.Expired(this, new EventArgs());
  54:                     }
  55:                 };
  56:                 if (sqlConnection.State != ConnectionState.Open)
  57:                 {
  58:                     sqlConnection.Open();
  59:                 }
  60:                 command.ExecuteNonQuery();
  61:             }
  62:         } 
  63:  
  64:         private void AddParameters(SqlCommand command, IDictionary<string, object> parameters)
  65:         {
  66:             command.Parameters.Clear();
  67:             foreach (var parameter in parameters)
  68:             {
  69:                 string parameterName = parameter.Key;
  70:                 if (!parameter.Key.StartsWith("@"))
  71:                 {
  72:                     parameterName = "@" + parameterName;
  73:                 } 
  74:  
  75:                 command.Parameters.Add(new SqlParameter(parameterName, parameter.Value));
  76:             }
  77:         } 
  78:  
  79:         #region ICacheItemExpiration Members 
  80:  
  81:         public bool HasExpired()
  82:         {
  83:             bool indicator = this.HasChanged;
  84:             this.HasChanged = false;
  85:             return indicator;
  86:         } 
  87:  
  88:         public void Initialize(CacheItem owningCacheItem)
  89:         {         } 
  90:  
  91:         public void Notify()
  92:         {         } 
  93:  
  94:         #endregion
  95:     }
  96: } 
  97:  

   1: private static readonly CommandType DefaultComamndType = CommandType.StoredProcedure; 
   2:  
   3: public event EventHandler Expired; 
   4:  
   5: public bool HasChanged
   6: { get; set; } 
   7:  
   8: public string ConnectionName
   9: { get; set; } 
  10:  

   1: if (string.IsNullOrEmpty(connectionStringName))
   2: {
   3:      this.ConnectionName = DatabaseSettings.GetDatabaseSettings(ConfigurationSourceFactory.Create()).DefaultDatabase;
   4: }
   5: else
   6: {
   7:      this.ConnectionName = connectionStringName;
   8: } 

   1: SqlDependency dependency = new SqlDependency(command);
   2: dependency.OnChange += delegate
   3: {
   4:       this.HasChanged = true;
   5:        if (this.Expired != null)
   6:        {
   7:               this.Expired(this, new EventArgs());
   8:  
   9:        }
  10:          
  11: };
  12:  

   1: public bool HasExpired()
   2: {
   3:      bool indicator = this.HasChanged;
   4:      this.HasChanged = false;
   5:      return indicator;
   6: } 

image

   1: ALTER PROCEDURE [dbo].[Message_Select_By_User]
   2: (@UserID    VarChar(50))
   3: AS
   4: BEGIN    
   5:     Select ID, UserID, [Message] From dbo.Messages Where UserID = @UserID
   6: END

注:如何写成Select * From dbo.Messages Where UserID = @UserID, SqlDependency 将不能正常运行;同时Table的也是必须的。

image

   1: private const string UserName = "Foo";
   2: private const string MessageCachingProcedure = "Message_Select_By_User";
   3: private const string CacheKey = "__MessageOfFoo"; 

   1: private SqlDependencyExpiration CacheItemExpiration
   2: {
   3:     get
   4:     {
   5:         IDictionary<string, object> parameters = new Dictionary<string, object>();
   6:         parameters.Add("UserID", UserName);
   7:         SqlDependencyExpiration expiration= new SqlDependencyExpiration(MessageCachingProcedure, parameters);
   8:         expiration.Expired += delegate
   9:         {
  10:             MessageBox.Show("Cache has expired!");
  11:         }; 
  12:  
  13:         return expiration;
  14:     }
  15: } 
  16:  

   1: private List<string> GetMessageByUser(string userName)
   2: {
   3:     List<string> messageList = new List<string>();
   4:     Database db = DatabaseFactory.CreateDatabase();
   5:     DbCommand command = db.GetStoredProcCommand(MessageCachingProcedure);
   6:     db.AddInParameter(command, "UserID", DbType.String, userName);
   7:     IDataReader reader = db.ExecuteReader(command);
   8:     while (reader.Read())
   9:     {
  10:         messageList.Add(reader.GetString(2));
  11:     } 
  12:  
  13:     return messageList;
  14: } 

   1: private List<string> GetMessages()
   2: {
   3:     ICacheManager manager = CacheFactory.GetCacheManager();
   4:     if (manager.GetData(CacheKey) == null)
   5:     { 
   6:         manager.Add(CacheKey, GetMessageByUser(UserName), CacheItemPriority.Normal, null, this.CacheItemExpiration);
   7:     } 
   8:  
   9:     return manager.GetData(CacheKey) as List<string>;
  10: } 

   1: private void CreateMessageEntry(string userName, string message)
   2: {
   3:     Database db = DatabaseFactory.CreateDatabase();
   4:     string insertSql = "INSERT INTO [dbo].[Messages]([UserID],[Message])VALUES(@userID, @message)";
   5:     DbCommand command = db.GetSqlStringCommand(insertSql);
   6:     db.AddInParameter(command, "userID", DbType.String, userName);
   7:     db.AddInParameter(command, "message", DbType.String, message);
   8:     db.ExecuteNonQuery(command);
   9: } 

   1: private void buttonAdd_Click(object sender, EventArgs e)
   2: {
   3:     this.CreateMessageEntry(this.comboBoxUserName.SelectedValue.ToString(), this.textBoxMessage.Text.Trim());
   4:     Thread.Sleep(1000);
   5:     this.listBoxMessage.DataSource = this.GetMessages();
   6: } 

image

image

   1: ALTER DATABASE MyDb SET ENABLE_BROKER ;

 


 

Enterprise Library深入解析与灵活应用:
[1] 通过Unity Extension实现和Policy Injection Application Block的集成
[2] 通过SqlDependency实现Cache和Database的同步
[3] 倘若将Unity、PIAB、Exception Handling引入MVP模式
[4] 创建一个自定义Exception Handler改变ELAB的异常处理机制
[5] 创建一个简易版的批处理执行器,认识Enterprise Library典型的配置方式和对象创建方式
[6] 自己动手创建迷你版AOP框架
[7] 再谈PIAB与Unity之间的集成



作者:蒋金楠
微信公众账号:大内老A
微博:www.weibo.com/artech
如果你想及时得到个人撰写文章以及着作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
原文链接

最后更新:2017-10-30 17:04:26

  上一篇:go  《EnterLib PIAB深入剖析》系列博文汇总
  下一篇:go  WCF后续之旅(11): 关于并发、回调的线程关联性(Thread Affinity)