基于 EntityFramework 的数据库主从读写分离架构(2)- 改进配置和添加事务支持
1 public class DbMasterSlaveCommandInterceptor : DbCommandInterceptor 2 { 3 private Lazy<string> masterConnectionString = new Lazy<string>(() => ConfigurationManager.AppSettings["masterConnectionString"]); 4 private Lazy<string> slaveConnectionString = new Lazy<string>(() => ConfigurationManager.AppSettings["slaveConnectionString"]); 5 6 public string MasterConnectionString 7 { 8 get { return this.masterConnectionString.Value; } 9 } 10 11 public string SlaveConnectionString 12 { 13 get { return this.slaveConnectionString.Value; } 14 } 15 16 17 public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) 18 { 19 this.UpdateConnectionStringIfNeed(interceptionContext, this.SlaveConnectionString); 20 } 21 22 public override void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) 23 { 24 this.UpdateConnectionStringIfNeed(interceptionContext, this.SlaveConnectionString); 25 } 26 27 public override void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) 28 { 29 this.UpdateConnectionStringIfNeed(interceptionContext, this.MasterConnectionString); 30 } 31 32 33 private void UpdateConnectionStringIfNeed(DbInterceptionContext interceptionContext, string connectionString) 34 { 35 foreach (var context in interceptionContext.DbContexts) 36 { 37 this.UpdateConnectionStringIfNeed(context.Database.Connection, connectionString); 38 } 39 } 40 41 /// <summary> 42 /// 此处改进了对连接字符串的修改判断机制,确认只在 <paramref name="conn"/> 所使用的连接字符串不等效于 <paramref name="connectionString"/> 的情况下才需要修改。 43 /// </summary> 44 /// <param name="conn"></param> 45 /// <param name="connectionString"></param> 46 private void UpdateConnectionStringIfNeed(DbConnection conn, string connectionString) 47 { 48 if (this.ConnectionStringCompare(conn, connectionString)) 49 { 50 ConnectionState state = conn.State; 51 if (state == ConnectionState.Open) 52 conn.Close(); 53 54 conn.ConnectionString = connectionString; 55 56 if (state == ConnectionState.Open) 57 conn.Open(); 58 } 59 } 60 61 private bool ConnectionStringCompare(DbConnection conn, string connectionString) 62 { 63 DbProviderFactory factory = DbProviderFactories.GetFactory(conn); 64 65 DbConnectionStringBuilder a = factory.CreateConnectionStringBuilder(); 66 a.ConnectionString = conn.ConnectionString; 67 68 DbConnectionStringBuilder b = factory.CreateConnectionStringBuilder(); 69 b.ConnectionString = connectionString; 70 71 return a.EquivalentTo(b); 72 } 73 }
再者,我们来聊聊数据库操作中的事务处理。
1 public class DbMasterSlaveCommandInterceptor : DbCommandInterceptor 2 { 3 private Lazy<string> masterConnectionString = new Lazy<string>(() => ConfigurationManager.AppSettings["masterConnectionString"]); 4 private Lazy<string> slaveConnectionString = new Lazy<string>(() => ConfigurationManager.AppSettings["slaveConnectionString"]); 5 6 public string MasterConnectionString 7 { 8 get { return this.masterConnectionString.Value; } 9 } 10 11 public string SlaveConnectionString 12 { 13 get { return this.slaveConnectionString.Value; } 14 } 15 16 17 public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) 18 { 19 this.UpdateToSlave(interceptionContext); 20 } 21 22 public override void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) 23 { 24 this.UpdateToSlave(interceptionContext); 25 } 26 27 public override void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) 28 { 29 this.UpdateToMaster(interceptionContext); 30 } 31 32 33 private void UpdateToMaster(DbInterceptionContext interceptionContext) 34 { 35 foreach (var context in interceptionContext.DbContexts) 36 { 37 this.UpdateConnectionStringIfNeed(context.Database.Connection, this.MasterConnectionString); 38 } 39 } 40 41 private void UpdateToSlave(DbInterceptionContext interceptionContext) 42 { 43 // 判断当前会话是否处于分布式事务中 44 bool isDistributedTran = Transaction.Current != null && Transaction.Current.TransactionInformation.Status != TransactionStatus.Committed; 45 foreach (var context in interceptionContext.DbContexts) 46 { 47 // 判断该 context 是否处于普通数据库事务中 48 bool isDbTran = context.Database.CurrentTransaction != null; 49 50 // 如果处于分布式事务或普通事务中,则“禁用”读写分离,处于事务中的所有读写操作都指向 Master 51 string connectionString = isDistributedTran || isDbTran ? this.MasterConnectionString : this.SlaveConnectionString; 52 53 this.UpdateConnectionStringIfNeed(context.Database.Connection, connectionString); 54 } 55 } 56 57 58 /// <summary> 59 /// 此处改进了对连接字符串的修改判断机制,确认只在 <paramref name="conn"/> 所使用的连接字符串不等效于 <paramref name="connectionString"/> 的情况下才需要修改。 60 /// <para>同时,在必要的情况下才会连接进行 Open 和 Close 操作以及修改 ConnectionString 处理,减少了性能的消耗。</para> 61 /// </summary> 62 /// <param name="conn"></param> 63 /// <param name="connectionString"></param> 64 private void UpdateConnectionStringIfNeed(DbConnection conn, string connectionString) 65 { 66 if (this.ConnectionStringCompare(conn, connectionString)) 67 { 68 this.UpdateConnectionString(conn, connectionString); 69 } 70 } 71 72 private void UpdateConnectionString(DbConnection conn, string connectionString) 73 { 74 ConnectionState state = conn.State; 75 if (state == ConnectionState.Open) 76 conn.Close(); 77 78 conn.ConnectionString = connectionString; 79 80 if (state == ConnectionState.Open) 81 conn.Open(); 82 } 83 84 private bool ConnectionStringCompare(DbConnection conn, string connectionString) 85 { 86 DbProviderFactory factory = DbProviderFactories.GetFactory(conn); 87 88 DbConnectionStringBuilder a = factory.CreateConnectionStringBuilder(); 89 a.ConnectionString = conn.ConnectionString; 90 91 DbConnectionStringBuilder b = factory.CreateConnectionStringBuilder(); 92 b.ConnectionString = connectionString; 93 94 return a.EquivalentTo(b); 95 } 96 }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。