EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~续~添加事务机制
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~续~添加事务机制,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4145字,纯文字阅读大概需要6分钟。
内容图文
![EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~续~添加事务机制](/upload/InfoBanner/zyjiaocheng/1265/2a938279bada408e85b10a4944e3a79e.jpg)
上一讲中简单介绍了一个EF环境下通过DbCommand拦截器来实现SQLSERVER的读写分离,只是一个最简单的实现,而如果出现事务情况,还是会有一些问题的,因为在拦截器中我们手动开启了Connection链接,而在一个WEB请求时,如果你的一个变量即用到了read库又用到了write库,就会导致到sqlserver端的spid(system process id,系统进程ID,sqlserver里可能是某个数据库进程序的ID)发生变化 ,而对于这种变化,原本是本地的事务就会自动提升为分布式事务,对MSDTC不了解的同学,可能看我的相关文章,所以,我们使用拦截实现读写分离后,在程序里,你的读和写的仓储对象要分别定义,不能共享,而且,你在事务里所以写的仓储对象都要使用同一个数据上下文!
当你按着我说的做后,本地事务就不会提升为msdtc了,如图:
今天我在DbCommand拦截器进行了优化,下面共享一下代码,如是测试不是真实一项目代码
/// <summary> /// SQL命令拦截器 /// </summary> public class SqlCommandInterceptor : DbCommandInterceptor { /// <summary> /// 读库,从库集群,写库不用设置走默认的EF框架 /// </summary> string readConn = System.Configuration.ConfigurationManager.AppSettings["readDb"] ?? string.Empty; privatestring GetReadConn() { var readArr = readConn.Split(newchar[] { ‘,‘ }, StringSplitOptions.RemoveEmptyEntries); var resultConn = string.Empty; if (readArr != null && readArr.Any()) { resultConn = readArr[Convert.ToInt32(Math.Floor((double)new Random().Next(0, readArr.Length)))]; } return resultConn; } //linq to entity生成的update,deletepublicoverridevoid NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) { base.NonQueryExecuting(command, interceptionContext);//update,delete等写操作直接走主库 } ///<summary>/// 执行sql语句,并返回第一行第一列,没有找到返回null,如果数据库中值为null,则返回 DBNull.Value ///</summary>///<param name="command"></param>///<param name="interceptionContext"></param>publicoverridevoid ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) { if (!string.IsNullOrWhiteSpace(GetReadConn()))//如果配置了读写分离,就去实现 { if (!command.CommandText.StartsWith("insert", StringComparison.InvariantCultureIgnoreCase)) { command.Connection.Close(); command.Connection.ConnectionString = GetReadConn(); command.Connection.Open(); } } base.ScalarExecuting(command, interceptionContext); } ///<summary>/// linq to entity生成的select,insert /// 发送到sqlserver之前触发 /// warning:在select语句中DbCommand.Transaction为null,而ef会为每个insert添加一个DbCommand.Transaction进行包裹 ///</summary>///<param name="command"></param>///<param name="interceptionContext"></param>publicoverridevoid ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { if (!string.IsNullOrWhiteSpace(GetReadConn()))//如果配置了读写分离,就去实现 { if (!command.CommandText.StartsWith("insert", StringComparison.InvariantCultureIgnoreCase)) { command.Connection.Close(); command.Connection.ConnectionString = GetReadConn(); command.Connection.Open(); } } base.ReaderExecuted(command, interceptionContext); } ///<summary>/// 发送到sqlserver之后触发 ///</summary>///<param name="command"></param>///<param name="interceptionContext"></param>publicoverridevoid ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { base.ReaderExecuted(command, interceptionContext); } }
运行程序可以设置一些测试代码
![技术分享](/upload/getfiles/default/2022/11/15/20221115110018610.jpg)
![技术分享](http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
public ActionResult Index() { IUnitOfWork db = new backgroundEntities(); IRepository<WebManageUsers> readUser = new BackgroundRepositoryBase<WebManageUsers>(); var a = readUser.GetModel().ToList();//读库using (var trans = new TransactionScope())//事务写库 { IRepository<WebManageUsers> userWrite = new BackgroundRepositoryBase<WebManageUsers>(db); IRepository<WebManageMenus> menuWrite = new BackgroundRepositoryBase<WebManageMenus>(db); var entity = new WebManageUsers { WebSystemID = 0, CreateDate = DateTime.Now, DepartmentID = 3, Description = "", Email = "", LoginName = "test", Mobile = "", Operator = "", Password = "", RealName = "test", Status = 1, UpdateDate = DateTime.Now, }; var entity2 = new WebManageMenus { ParentID = 1, About = "", LinkUrl = "", MenuLevel = 1, MenuName = "test", Operator = "", SortNumber = 1, Status = 1, UpdateDate = DateTime.Now, }; userWrite.Insert(entity); menuWrite.Insert(entity2); trans.Complete(); } return View(a); }
最后的结果就是我们想要的,这里说明一点,仓储大步的读写分离没有数据库压力这块的考虑,只是随机去访问某个读库。
原文:http://www.cnblogs.com/lori/p/4210796.html
内容总结
以上是互联网集市为您收集整理的EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~续~添加事务机制全部内容,希望文章能够帮你解决EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~续~添加事务机制所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。