基于 EntityFramework 的数据库主从读写分离架构(2)- 改进配置和添加事务支持
public class DbMasterSlaveCommandInterceptor : DbCommandInterceptor
{
private Lazy<string> masterConnectionString = new Lazy<string>(() => ConfigurationManager.AppSettings["masterConnectionString"]);
private Lazy<string> slaveConnectionString = new Lazy<string>(() => ConfigurationManager.AppSettings["slaveConnectionString"]); public string MasterConnectionString
{
get { return this.masterConnectionString.Value; }
} public string SlaveConnectionString
{
get { return this.slaveConnectionString.Value; }
} public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
this.UpdateConnectionStringIfNeed(interceptionContext, this.SlaveConnectionString);
} public override void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
{
this.UpdateConnectionStringIfNeed(interceptionContext, this.SlaveConnectionString);
} public override void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
{
this.UpdateConnectionStringIfNeed(interceptionContext, this.MasterConnectionString);
} private void UpdateConnectionStringIfNeed(DbInterceptionContext interceptionContext, string connectionString)
{
foreach (var context in interceptionContext.DbContexts)
{
this.UpdateConnectionStringIfNeed(context.Database.Connection, connectionString);
}
} /// <summary>
/// 此处改进了对连接字符串的修改判断机制,确认只在 <paramref name="conn"/> 所使用的连接字符串不等效于 <paramref name="connectionString"/> 的情况下才需要修改。
/// </summary>
/// <param name="conn"></param>
/// <param name="connectionString"></param>
private void UpdateConnectionStringIfNeed(DbConnection conn, string connectionString)
{
if (this.ConnectionStringCompare(conn, connectionString))
{
ConnectionState state = conn.State;
if (state == ConnectionState.Open)
conn.Close(); conn.ConnectionString = connectionString; if (state == ConnectionState.Open)
conn.Open();
}
} private bool ConnectionStringCompare(DbConnection conn, string connectionString)
{
DbProviderFactory factory = DbProviderFactories.GetFactory(conn); DbConnectionStringBuilder a = factory.CreateConnectionStringBuilder();
a.ConnectionString = conn.ConnectionString; DbConnectionStringBuilder b = factory.CreateConnectionStringBuilder();
b.ConnectionString = connectionString; return a.EquivalentTo(b);
}
}
再者,我们来聊聊数据库操作中的事务处理。
public class DbMasterSlaveCommandInterceptor : DbCommandInterceptor
{
private Lazy<string> masterConnectionString = new Lazy<string>(() => ConfigurationManager.AppSettings["masterConnectionString"]);
private Lazy<string> slaveConnectionString = new Lazy<string>(() => ConfigurationManager.AppSettings["slaveConnectionString"]); public string MasterConnectionString
{
get { return this.masterConnectionString.Value; }
} public string SlaveConnectionString
{
get { return this.slaveConnectionString.Value; }
} public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
this.UpdateToSlave(interceptionContext);
} public override void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
{
this.UpdateToSlave(interceptionContext);
} public override void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
{
this.UpdateToMaster(interceptionContext);
} private void UpdateToMaster(DbInterceptionContext interceptionContext)
{
foreach (var context in interceptionContext.DbContexts)
{
this.UpdateConnectionStringIfNeed(context.Database.Connection, this.MasterConnectionString);
}
} private void UpdateToSlave(DbInterceptionContext interceptionContext)
{
// 判断当前会话是否处于分布式事务中
bool isDistributedTran = Transaction.Current != null && Transaction.Current.TransactionInformation.Status != TransactionStatus.Committed;
foreach (var context in interceptionContext.DbContexts)
{
// 判断该 context 是否处于普通数据库事务中
bool isDbTran = context.Database.CurrentTransaction != null; // 如果处于分布式事务或普通事务中,则“禁用”读写分离,处于事务中的所有读写操作都指向 Master
string connectionString = isDistributedTran || isDbTran ? this.MasterConnectionString : this.SlaveConnectionString; this.UpdateConnectionStringIfNeed(context.Database.Connection, connectionString);
}
} /// <summary>
/// 此处改进了对连接字符串的修改判断机制,确认只在 <paramref name="conn"/> 所使用的连接字符串不等效于 <paramref name="connectionString"/> 的情况下才需要修改。
/// <para>同时,在必要的情况下才会连接进行 Open 和 Close 操作以及修改 ConnectionString 处理,减少了性能的消耗。</para>
/// </summary>
/// <param name="conn"></param>
/// <param name="connectionString"></param>
private void UpdateConnectionStringIfNeed(DbConnection conn, string connectionString)
{
if (this.ConnectionStringCompare(conn, connectionString))
{
this.UpdateConnectionString(conn, connectionString);
}
} private void UpdateConnectionString(DbConnection conn, string connectionString)
{
ConnectionState state = conn.State;
if (state == ConnectionState.Open)
conn.Close(); conn.ConnectionString = connectionString; if (state == ConnectionState.Open)
conn.Open();
} private bool ConnectionStringCompare(DbConnection conn, string connectionString)
{
DbProviderFactory factory = DbProviderFactories.GetFactory(conn); DbConnectionStringBuilder a = factory.CreateConnectionStringBuilder();
a.ConnectionString = conn.ConnectionString; DbConnectionStringBuilder b = factory.CreateConnectionStringBuilder();
b.ConnectionString = connectionString; return a.EquivalentTo(b);
}
}
基于 EntityFramework 的数据库主从读写分离架构(2)- 改进配置和添加事务支持的更多相关文章
- 基于 EntityFramework 的数据库主从读写分离架构 - 目录
基于 EntityFramework 的数据库主从读写分离架构 回到目录,完整代码请查看(https://github.com/cjw0511/NDF.Infrastructure)中的目 ...
- 基于 EntityFramework 的数据库主从读写分离架构(1) - 原理概述和基本功能实现
回到目录,完整代码请查看(https://github.com/cjw0511/NDF.Infrastructure)中的目录: src\ NDF.Data.EntityFramew ...
- 基于 EntityFramework 的数据库主从读写分离服务插件
基于 EntityFramework 的数据库主从读写分离服务插件 1. 版本信息和源码 1.1 版本信息 v1.01 beta(2015-04-07),基于 EF 6.1 开发,支持 EF 6.1 ...
- 基于 EntityFramework 的数据库主从读写分离
现在刚开始来研究EntityFramwork,起初是在vs2012中通过工具来创建EF ,但是对我这种不熟悉菜鸟来说 有很多业务用EF做出来还是有点难度的,今天来手动搭建一个EF框架,大神勿喷
- 基于Amoba实现mysql主从读写分离
一.Amoeba简介 Amoeba是一个以MySQL为底层数据存储,并对应用提供MySQL协议接口的proxy.它集中地响应应用的请求,依据用户事先设置的规则,将SQL请求发送到特 ...
- Amoeba搞定mysql主从读写分离
前言:一直想找一个工具,能很好的实现mysql主从的读写分离架构,曾经试用过mysql-proxy发现lua用起来很不爽,尤其是不懂lua脚本,突然发现了Amoeba这个项目,试用了下,感觉还不错,写 ...
- MySQL搭建主从数据库 实现读写分离
首先声明,实际生产中,网站为了提高用户体验,性能等,将数据库实现读写分离是有必要的,我们让主数据库去写入数据,然后当用户查询的时候,然后在从数据库读取数据,故能减轻数据库的压力,实现良好的用户体验! ...
- Amoeba实现mysql主从读写分离
Amoeba实现mysql主从读写分离 这段在网上看了下关于amoeba的文章,总体感觉好像要比mysql-proxy好的多,也参考了不少的资料,此文章可能与其他文章作者会有雷同的地方,请谅解,但是此 ...
- Mycat - 实现数据库的读写分离与高可用
前言 开心一刻 上语文课,不小心睡着了,坐在边上的同桌突然叫醒了我,并小声说道:“读课文第三段”.我立马起身大声读了起来.正在黑板写字的老师吓了一跳,老师郁闷的看着我,问道:“同学有什么问题吗?”,我 ...
随机推荐
- Python学习系列(四)(列表及其函数)
Python学习系列(四)(列表及其函数) Python学习系列(一)(基础入门) Python学习系列(二)(基础知识) Python学习系列(三)(字符串) 一.基本概念 1,列表是什么? ...
- jmeter --- 测试计划里的元件
1.线程组 线程组元件是任何一个测试计划的开始点.在一个测试计划中的所有元件都必须在某个线程组下.顾名思义,线程组元件控制JMeter执行你的测试计划时候使用的线程数量.对线程组的控制允许你: 设置线 ...
- zabbix 触发器 | count 函数
摘要:确认多次zabbix监控中小编用的最多的是count的这函数,确认多次以减少了很多误告警,提高了运维效率.可以设置连续几次都异常才发出告警,这样一来,只要发出告警基本上就已经确定发生故障了.co ...
- SourceTree使用介绍
SourceTree比命令行更容易操作,能更直观看到发生了什么.但是没有哪一家git图形化软件能完成git的所有操作,封装后的使用也隐藏了git的一些细节,在图形化工具出现一些非常罕见的情况时,还是需 ...
- 蓝桥杯 算法训练 ALGO-50 数组查找及替换
算法训练 数组查找及替换 时间限制:1.0s 内存限制:512.0MB 问题描述 给定某整数数组和某一整数b.要求删除数组中可以被b整除的所有元素,同时将该数组各元素按从小到大排序.如果数组元 ...
- 蓝桥杯 算法训练 ALGO-21 装箱问题
算法训练 装箱问题 时间限制:1.0s 内存限制:256.0MB 问题描述 有一个箱子容量为V(正整数,0<=V<=20000),同时有n个物品(0<n<=30),每 ...
- chrome瀏覽器去掉緩存的方法
方法一: 1.開發說打開開發者工具 勾選這個訪問可以 方法二: command+shift+R
- 【转】Jmeter分布式部署文档
很多时候,我们测试时,如果进行大数据量的并发测试时,单个电脑的CPU和内存可能无法承受,这个时候,我们需要进行一个分布式的测试,比如10000个并发,使用三台电脑来进行并发,Jmeter提供了这种功能 ...
- Ansible之Playbooks的when语句
在使用ansible做自动化运维的时候,大多数情况下都执行某些任务的时候都需要依赖某个变量的值或者是上一个任务的执行结果.如,根据facts信息中的系统版本相关的信息来确定使用哪种包管理器安装软件.A ...
- spring-cloud配置服务器配置
本文介绍spring-cloud配置服务器 server端配置 目录结构 依赖 java代码 properties 运行 client端配置 目录结构 依赖 java代码 properties 运行 ...