EntityFramework Core进行读写分离最佳实践方式,了解一下(二)?

网友投稿 753 2022-05-30

EF Core读写分离进一步完善

如评论前辈们指出在EF 6.x中我们知道有IDbCommandInterceptor接口,我们可对执行的SQL语句进行拦截,从而可自定义实现我们想要的需求,虽然在EF Core中却没有拦截器特性的实现,但是针对此特性的实现DiagnosticSource记录跟踪类来实现等效于拦截器的实现,当前DiagnosticSource使用文档尚未完善,估计还得等待一段时间,接下来我们来看看如何实现。在DiagnosticSource包中有DiagnosticListener类,我们通过此类来跟踪记录,如果执行的EF Core包,那么我们将利用DiagnosticListener进行订阅,订阅到之后我们拿到跟踪命令,从而实现无感知更换数据库,代码如下:

public class DbCommandInterceptor : IObserver>     {        private const string masterConnectionString = "data source=WANGPENG;User Id=sa;Pwd=sa123;initial catalog=Demo1;integrated security=True;";        private const string slaveConnectionString = "data source=WANGPENG;User Id=sa;Pwd=sa123;initial catalog=Demo2;integrated security=True;";        public void OnCompleted()         {         }        public void replaceString(Exception error)         {         }        public void OnNext(KeyValuePair value)         {            if (value.Key == RelationalEventId.CommandExecuting.Name)             {                var command = ((CommandEventData)value.Value).Command;                var executeMethod = ((CommandEventData)value.Value).ExecuteMethod;                if (executeMethod == DbCommandMethod.ExecuteNonQuery)                 {                     ResetConnection(command, masterConnectionString);                 }                else if (executeMethod == DbCommandMethod.ExecuteScalar)                 {                     ResetConnection(command, slaveConnectionString);                 }                else if (executeMethod == DbCommandMethod.ExecuteReader)                 {                     ResetConnection(command, slaveConnectionString);                 }             }         }        void ResetConnection(DbCommand command, string connectionString)         {            if (command.Connection.State == ConnectionState.Open)             {                if (!command.CommandText.Contains("@@ROWCOUNT"))                 {                     command.Connection.Close();                     command.Connection.ConnectionString = connectionString;                 }             }            if (command.Connection.State == ConnectionState.Closed)             {                 command.Connection.Open();             }         }     }

这里存在一个问题,上述 command.CommandText.Contains("@@ROWCOUNT") 代码,因为在进行添加操作时,会返回主键,那么此时会进行查询,所以暂时没有更好的方式是确认主-从数据库。

public class CommandListener : IObserver     {        private readonly DbCommandInterceptor _dbCommandInterceptor = new DbCommandInterceptor();        public void OnCompleted()         {         }        public void replaceString(Exception error)         {         }        public void OnNext(DiagnosticListener listener)         {              if (listener.Name == DbLoggerCategory.Name)             {                 listener.Subscribe(_dbCommandInterceptor);             }         }     }

上述 DbLoggerCategory.Name 也就是 Microsoft.EntityFrameworkCore ,通过监控的包是Microsoft.EntityFrameworkCore,则进行订阅,最后我们在startup中进行注册该监听类。

DiagnosticListener.AllListeners.Subscribe(new CommandListener());

接下来我们通过动态图来看看最终实际效果,主-从复制依然是通过SQL Server发布-订阅的方式来同步数据。在控制器中,我们只利用demo1上下文来添加和查询数据,当查询时更换到从数据库,此时已是无感知(请见上一篇),如下:

[HttpGet("index")]        public IActionResult Index()         {            var blogs = _demo1DbContext.Blogs.ToList();            return View(blogs);         }         [HttpGet("create")]        public IActionResult CreateDemo1Blog()         {            var blog = new Blog()             {                 Name = "demoBlog1",                 Url = "http://www.cnblogs.com/createmyslef"             };             _demo1DbContext.Blogs.Add(blog);             _demo1DbContext.SaveChanges();            return RedirectToAction(nameof(Index));         }

总结

EntityFramework Core进行读写分离最佳实践方式,了解一下(二)?

本文只是在上一篇的基础上进一步改善了读写分离的操作,得益于github上有提出可通过跟踪记录来解决,通过跟踪记录从底层出发来完善读写分离操作,我们可拿到底层实现的命令以及其他和EF 6.x中利用拦截器等效,至于更加复杂的逻辑可自行实现。

数据库

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:SQLite 并发的四种处理方式
下一篇:[经验]解决使用opencv 高分辨率下的摄像头卡顿不流畅
相关文章