EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~续~添加事务机制

本文涉及的产品
云数据库 RDS SQL Server,独享型 2核4GB
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
简介:

上一讲中简单介绍了一个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;
        private string GetReadConn()
        {
            var readArr = readConn.Split(new char[] { ',' }, 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,delete
        public override void 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>
        public override void 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>
        public override void 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>
        public override void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
        {
            base.ReaderExecuted(command, interceptionContext);
        }
    }

运行程序可以设置一些测试代码

  View Code

最后的结果就是我们想要的,这里说明一点,仓储大步的读写分离没有数据库压力这块的考虑,只是随机去访问某个读库。

本文转自博客园张占岭(仓储大叔)的博客,原文链接:EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~续~添加事务机制,如需转载请自行联系原博主。

相关实践学习
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS&nbsp;SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/sqlserver
目录
相关文章
|
3天前
|
网络协议 安全 分布式数据库
技术分享:分布式数据库DNS服务器的架构思路
技术分享:分布式数据库DNS服务器的架构思路
8 0
|
4天前
|
SQL 存储 运维
网易游戏如何基于阿里云瑶池数据库 SelectDB 内核 Apache Doris 构建全新湖仓一体架构
随着网易游戏品类及产品的快速发展,游戏数据分析场景面临着越来越多的挑战,为了保证系统性能和 SLA,要求引入新的组件来解决特定业务场景问题。为此,网易游戏引入 Apache Doris 构建了全新的湖仓一体架构。经过不断地扩张,目前已发展至十余集群、为内部上百个项目提供了稳定可靠的数据服务、日均查询量数百万次,整体查询性能得到 10-20 倍提升。
网易游戏如何基于阿里云瑶池数据库 SelectDB 内核 Apache Doris 构建全新湖仓一体架构
|
6天前
|
存储 SQL Oracle
主流关系型数据库存储架构层的差异分析
主流关系型数据库存储架构层的差异分析
|
7天前
|
SQL Java 数据库连接
如何在Java中实现数据库事务?
如何在Java中实现数据库事务?
|
7天前
|
NoSQL Java 数据库
优化基于阿里云的微服务架构下的数据库访问性能
在应对大型电商项目中数据库访问性能瓶颈问题时,团队通过阿里云工具分析发现高QPS、慢查询和不合理数据交互是关键。优化措施包括:1) 索引优化,针对慢查询添加或调整索引;2) 开启读写分离,使用RDS读写分离功能和DRDS进行水平拆分;3) 引入Redis缓存热点数据,减少直接数据库访问;4) 服务化数据访问,降低跨服务数据库调用;5) 使用Sentinel进行限流和熔断,保护数据库资源。这些改进显著提升了系统响应速度和用户体验。
|
8天前
|
SQL Java 关系型数据库
JAVA数据库开发 - 事务
JAVA数据库开发 - 事务
17 0
|
14天前
|
存储 关系型数据库 MySQL
MySQL数据库进阶第六篇(InnoDB引擎架构,事务原理,MVCC)
MySQL数据库进阶第六篇(InnoDB引擎架构,事务原理,MVCC)
|
19小时前
|
负载均衡 监控 Java
Java中的可扩展微服务架构
Java中的可扩展微服务架构
|
19小时前
|
负载均衡 Java API
Java微服务架构中的API网关设计与实现
Java微服务架构中的API网关设计与实现
|
1天前
|
负载均衡 Java 开发者
细解微服务架构实践:如何使用Spring Cloud进行Java微服务治理
【7月更文挑战第1天】Spring Cloud是Java微服务治理明星框架,整合Eureka(服务发现)、Ribbon(客户端负载均衡)、Hystrix(熔断器)、Zuul(API网关)和Config Server(配置中心),提供完整服务治理解决方案。通过Eureka实现服务注册与发现,Ribbon进行客户端负载均衡,Hystrix确保服务容错,Config Server集中管理配置,Zuul作为API网关简化系统复杂性。理解和使用Spring Cloud是现代Java开发者的关键技能。
13 0