EF架構~通(tong)過EF6的DbCommand攔截器來實現數據庫讀(du)寫分離
前幾天看了一個基于sqlserver的(de)(de)負載均衡與(yu)讀(du)寫分(fen)離的(de)(de)軟件Moebius,實現的(de)(de)方式還是不(bu)錯的(de)(de),這使得用sqlserver數(shu)據(ju)庫(ku)的(de)(de)同學時有(you)機(ji)會對(dui)數(shu)據(ju)庫(ku)進行更有(you)效的(de)(de)優(you)化(hua)了
看著人有(you)做的(de)東(dong)西,自(zi)己(ji)也(ye)想用EF來實現(xian)一(yi)個讀寫(xie)分離,所以(yi)就(jiu)有(you)了本(ben)篇文(wen)章,倉儲大叔(shu)讀寫(xie)分離的(de)思(si)路是(shi):
1 用(yong)sqlserver自帶(dai)的發布、訂(ding)閱實現(xian)主,從數據(ju)庫的結構,同步這事由(you)sql幫我們(men)完成
2 配置文件建立幾個供只讀的數據庫(ku)連接(jie)串
3 建立SQL命令攔截器(qi)
4 修改大叔的DbContextRepository基(ji)數,添加(jia)攔(lan)截行(xing)為
5 測試,搞定
有了上面(mian)的想法,咱就可以(yi)(yi)干事了,第一步不用說了,可以(yi)(yi)自己百度(du),從第2步說起
2 配置文件建立幾個供只讀的數據庫連接串
<!-- 只寫-->
<add name="backgroundEntities" connectionString="metadata=res://*/background.csdl|res://*/background.ssdl|res://*/background.msl;provider=System.Data.SqlClient;provider connection string="data source=.;initial catalog=background;persist security info=True;user id=sa;password=zzl123;multipleactiveresultsets=True;application name=EntityFramework"" providerName="System.Data.EntityClient" />
<!-- 只讀-->
<add name="backgroundEntitiesRead" connectionString="metadata=res://*/background.csdl|res://*/background.ssdl|res://*/background.msl;provider=System.Data.SqlClient;provider connection string="data source=.;initial catalog=background_Read1;persist security info=True;user id=sa;password=zzl123;multipleactiveresultsets=True;application name=EntityFramework"" providerName="System.Data.EntityClient" />
3 建立SQL命令攔截器
/// <summary> /// SQL命令攔截器 /// </summary> public class NoLockInterceptor : DbCommandInterceptor { private static readonly Regex _tableAliasRegex = new Regex(@"(?<tableAlias>AS \[Extent\d+\](?! WITH \(NOLOCK\)))", RegexOptions.Multiline | RegexOptions.IgnoreCase); [ThreadStatic] public static bool SuppressNoLock; public override void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) { string conn = command.Connection.ConnectionString; base.NonQueryExecuting(command, interceptionContext); } public override void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) { command.Connection.Close(); command.Connection.ConnectionString = "data source=.;initial catalog=background_Read1;persist security info=True;user id=sa;password=zzl123;multipleactiveresultsets=True;application name=EntityFramework"; command.Connection.Open(); if (!SuppressNoLock) { command.CommandText = _tableAliasRegex.Replace(command.CommandText, "${tableAlias} WITH (NOLOCK)"); } } public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { command.Connection.Close(); command.Connection.ConnectionString = "data source=.;initial catalog=background_Read1;persist security info=True;user id=sa;password=zzl123;multipleactiveresultsets=True;application name=EntityFramework"; command.Connection.Open(); if (!SuppressNoLock) { command.CommandText = _tableAliasRegex.Replace(command.CommandText, "${tableAlias} WITH (NOLOCK)"); } } }
4 修改大叔的DbContextRepository基數,添加攔截行為
public DbContextRepository(IUnitOfWork db, Action<string> logger) { UnitWork = db; Db = (DbContext)db; Logger = logger; ((IObjectContextAdapter)Db).ObjectContext.CommandTimeout = 0; //SQL語(yu)句攔(lan)截器(qi) System.Data.Entity.Infrastructure.Interception.DbInterception.Add(new EntityFrameworks.Data.Core.Common.NoLockInterceptor()); EntityFrameworks.Data.Core.Common.NoLockInterceptor.SuppressNoLock = true; }
5 大功造成,感謝閱讀!
本(ben)文章代碼沒有全部展(zhan)示,只是展(zhan)示一種思想,希(xi)望可以(yi)給大家(jia)帶來(lai)幫助。