事务使用中如何避免误用分布式事务(System.Transactions.TransactionScope)
本地事务:这个没什么好说了,就是单个事务,每种数据库都有自己的实现,事务的深度内涵可以搜索查看相关的文章,不是本文介绍的重点。
1.2:System.Transactions.TransactionScope:分布式事务,需要添加引用System.Transactions,同时启用MSDTC分布式事务服务:通常使用方式为:
using (System.Transactions.TransactionScope ts = new System.Transactions.TransactionScope()){
//代码块A
//代码块B
ts.Complete();//提交事务
}
分布式事务本质上是引入了第三方裁判,来想办法对多个本地事务监控同时成功或同时失败,这里分享几个知识点:
A:如果代码块里,若存在两个或以上数据库链接DbConnection,则需要启动微软的MSDTC分布式事务服务。
用命令行启动或停止服务:
B:如果代码块里,只有一个数据库链接DbConnection,那么实际上只是本地事务在处理,就算MSDTC分布式事务服务没启动,也不会报错。
C:对于TransactionScope包含的代码块,本质是监控了代码块里数据库链接DbConnection的个数,如果有多个不同的对象,则引入MSDTC当裁判,而实际执行的事务的还是各个本地事务。
D:MSDTC总是不够稳定,我在测试时两个简单的事务一起时,按住F5不停刷新,竟然能把MSSQL服务也给挂了,而用本地事务就算跨库也不会有问题。
所以,不是必须的情况,尽量不要引入分布式事务,应该避免使用TransactionScope来包含事务块的冲动。
问题:一个代码块里N个实体类杂交操作,每个实体类带有各种的数据库链接,从而引发了MSDTC。
可以:共用一个DbConnection对象,来避免启用MSDTC。2.2:项目多个数据库,如果数据库间使用了相同的访问账号和密码,这种情况也可以避免:
每种数据库有自己的解决方式:像MSSQL,跨库处理只要加前缀(dbname..tablename)就可以,因此也使的只使用本地事务就可以处理了。
3:回顾下我以前的项目场景: 3.1:从下图是我08年在中域的项目:有19个数据库,对于数据库链接而言,唯一的不同只有数据库的名称:
进化:能不能只保留一条,其它的通过动态切换数据库名称来改链接字符串?
3.2:那时候,我的架构还是很新手,通过CodeSmith生成了大量的代码文件:
实体类项目,工厂项目,接口项目,数据操作,还有大量的增删改查存储过程,只是为了基础的增删改查而且只针对MSSQL。
随便展开一个项目都会看到大量的文件夹,里面有大量的文件,而这些东东,都是代码生成器的杰作:
19个数据库啊,NN个表,光生成这些基本的增删改查,整个项目就好像高端大气上档次了。
进化:能不能消灭这些大量的文件,简单是我们不断追求的目标。3.3:这么多数据库,如何跨数据库事务?
对于生成的大量的实体,每个表的操作都是一个新的链接,单库间的事务都必须MSDTC了,更别说19个库间的跨库事务了。
进化:能不能本地事务搞定这些,这是每个ORM可以思考的方向。4:CYQ.Data 提供的解决方案:
为了消灭上述的那些大量的生成文件,我在后续新的公司写了传统的ORM框架:XQData(这个框架一直没露过面,也只是支持MSSQL,用反射消灭了好多层,只留下实体层)。
对于框架的演进,多数都来源于项目中遇到的问题,或复杂的场景,需要解决或者简化,才有了不断升级的可能,并不是无中生有,因此,一个框架,如果不能不断在在项目中实战,那么很多问题和细节等可能都无法发现,更新也会遥遥无期。
而CYQ.Data的不断升级,说明我一直在奋战在一线的编码生涯中和网友各大项目中的实战反馈中。
下面针对最近的优化调整,演示下CYQ.Data是怎么解决上面提到的几个问题:
4.1:多个数据库的数据库链接切换:A:先用配置工具生成针对多数据库的枚举文件,和成demo和test两个数据库:
两个数据库就生成两次了。
B:配置一个默认的链接字符串,到Demo数据库:
add name="Conn" connectionString="server=.;database=demo;uid=sa;pwd=123456"/C:打印操作Test数据库表的链接字符串:
输出:
这里自动切换了数据为名称为新的链接,而我动手脚的地方就是在枚举的名称了。 4.2:本地多数据库跨事务,示例: AppDebug.OpenDebugInfo = true;
AppDebug.Start();
using (MAction action = new MAction(DemoEnum.Users))
{
action.BeginTransation();//开启事务
action.Fill(12);
Console.WriteLine(action.ConnectionString);//打印数据库链接
action.ResetTable(TestEnum.Users);//切换数据库
Console.WriteLine(action.ConnectionString);//打印数据库链接
action.Fill(12);
action.EndTransation();
}
Console.WriteLine(AppDebug.Info);//输出所有执行的SQL语句。
AppDebug.Stop();
输出的结果:
说明:在事务中,当检测到事务开启时,为了使用本地事务,并没有切换数据库,而是采用了前缀来执行操作。
如果注释掉代码中的事务,则是直接切换数据库链接,输出会如下图:
说明:如果没有开启事务,则直接切换了数据库链接,并消消灭前缀语法。
对于.NET领域,微软除了提供这个不太稳定的MSDTC,似乎没有发现其它分布式事务的解决方案,好在一般的项目,我们在本地事务就可以处理。
希望微软可以在一些重点分布式上多做点研究、普及和推广,提供分布式相关项目的解决方案,别整天操碎心在那些简单的增删改查上。
【事务与锁】当Transactional遇上synchronized 最近工作中遇到某些七七八八的问题,就是与事务和锁、并发都有着紧密联系相关的问题所在。主要情况是:通过调用方法获取编号,而这个编号是递增有序的,并且存在于数据库中,简单理解就是需要用到这种编号(以下称任务编号),需要从数据库获取出来,在+1最为本次需要的编号,然后在存回数据库中,提供下次使用。
原子性(Atomic):事务中各项操作,要么全做要么全不做,任何一项操作的失败都会导致整个事务的失败; 一致性(Consistent):事务结束后系统状态是一致的; 隔离性(Isolated):并发执行的事务彼此无法看到对方的中间状态; 持久性(Durable):事务完成后所做的改动都会被持久化,即使发生灾难性的失败。
数据库事务的四大特性以及事务的隔离级别 数据库事务的四大特性以及事务的隔离级别http://www.bieryun.com/3118.html 本篇讲诉数据库中事务的四大特性(ACID),并且将会详细地说明事务的隔离级别。 如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: ⑴ 原子性(Atomicity) 原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,这和前面两篇博客介绍事务的功能是一样的概念,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
相关文章
- 使用kafka消息队列解决分布式事务(可靠消息最终一致性方案-本地消息服务)
- spring boot:shardingsphere+druid多数据源整合seata分布式事务(spring boot 2.3.3)
- 说说分布式事务
- Android学习---SQLite数据库的增删改查和事务(transaction)调用
- 【转】分布式事务中常见的三种解决方案
- MySQL事务与MVVC
- Java数据库篇5——事务
- TX-LCN分布式事务框架开发文档
- 在 SAP Fiori Gateway 系统配置一个指向 SAPGUI 事务的 tile
- 如何通过一个SAPGUI屏幕反查这个屏幕对应的事务码
- Atitit db access req数据库访问规范jdo jdbc jpa pdo sql 目录 1. 常见特性1 1.1. 元数据 API1 1.2. 分布式事务 vs事务中使用 Sav
- 数据库的事务
- 再有人问你分布式事务,把这篇扔给他
- cassandra mongodb选择——cassandra:分布式扩展好,写性能强,以及可以预料的查询;mongodb:非事务,支持复杂查询,但是不适合报表
- 04 _ 如何利用事务消息实现分布式事务?
- RabbitMQ之消息确认机制(事务+Confirm)
- .NET Core 事件总线,分布式事务解决方案:CAP
- mysql InnoDB事务
- MySQL中基于XA实现的分布式事务