一、什么是TransactionScope?

  TransactionScope即范围事务(类似数据库中的事务),保证事务声明范围内的一切数据修改操作状态一致性,要么全部成功,要么全部失败回滚.

  MSDN:如果在事务范围内未不发生任何异常 (即之间的初始化 TransactionScope 对象并调用其 Dispose 方法),则范围所参与的事务可以继续,否则参与到其中的事务将回滚。
      当应用程序完成所有工作时它想要在事务中执行,应调用 Complete 方法一次,以通知该事务管理器是可接受(此时事务并未提交),即可提交事务,未能调用此方法中止事务。
      调用 Dispose 方法将标记事务范围的末尾。 在调用此方法之后所发生的异常不会影响事务。

二、TransactionScope有什么用?

  假如现在有一个需求:实现一个下单功能,主要业务包含扣减商品库存、扣减用户账户余额、生成订单记录以及记录日志。为了保证数据一致性我们通常的做法就是在数据库建一个下订单的事务,然后程序调用事务传入相应的参数即可。那么问题来了,如果用户的账户数据跟订单数据分别处于不同的数据库,就没法在同一个数据库事务里完成所有任务,也就没法保证数据的一致性。
  最近由于业务的变更公司改用MySQL数据库,处理数据变更时习惯性先写事务,写的时候发现现有数据库中一个事务都没有,于是去问java组,不使用事务怎么保证数据的一致性?得到的答复是:事务是什么鬼,spring帮我们解决所有问题...。立马就懵逼了,.net中没听说有Spring啊(据说有类似的框架),虽然可以考虑使用仓储加工作单元来解决,但是感觉好麻烦的样子,后来寻找解决方案时发现了TransactionScope。

三、TransactionScope怎么使用?

 try
{
using (TransactionScope scope = new TransactionScope())
{
//TODO:数据处理业务
scope.Complete();
}
}
catch (Exception ex)
{
throw ex;
}

四、问题探讨

1、准备工作

 //数据库访问对象
public class Studuent
{
public static IList<StudentModel> GetList()
{
//不允许脏读
string sql = "SELECT Id,Name,CreateTime FROM Student ORDER BY Id DESC;";
DataTable dt = SQLHelper.ExecuteDataTable(CommandType.Text, sql);
return dt.ToModel<StudentModel>();
} public static bool Add(string name)
{
SqlParameter[] parms = { new SqlParameter("@Name", SqlDbType.NVarChar, ) { Value = name } };
string sql = "INSERT INTO Student (Name) VALUES (@Name)";
return SQLHelper.ExecuteNonQuery(CommandType.Text, sql, parms) > ;
} public static void Clear()
{
SQLHelper.ExecuteNonQuery("DELETE Student");
}
}
 //公共方法,输出学生列表
static void PrintStudent()
{
IList<StudentModel> list = Studuent.GetList();
foreach (var item in list)
{
Console.WriteLine("{0}\t{1}\t{2}", Thread.CurrentThread.ManagedThreadId, item.Name, item.CreateTime);
}
Console.WriteLine();
}

2、事务什么时候提交?

最初我以为在执行Complete后即刻提交,但根据输出结果可以看出,Complete方法执行两秒之后事务依旧没有提交。因为不允许脏读的原因,主线程会在事务对Student表操作完成后才可查询完成,但学生列表是在scope调用dispose方法之后输出,MSDN介绍说dispose确定事务范围末尾,因此猜测事务是在调用dispose时被提交。

3、异常是怎么导致数据不被提交?

对比两幅图可以看出,异常在Complete之后发生并不会影响事务的提交,事务未提交是因为发生异常导致Complete未被执行。之前看过一篇文章说,如果TransactionScope范围中没有调用Complete会导致程序异常,我想他肯定是开玩笑的...

4、嵌套事务

探索逻辑事务 TransactionScope的更多相关文章

  1. 分布式事务TransactionScope

    分布式事务TransactionScope 以下是分布式事务的所有情况的例子了,包含了事务套事务,事务套存储过程事务,经过测试,TransactionScope对于分布式事务的各种情况支持的很好. 使 ...

  2. 代码块事务—TransactionScope

    今天上班遇到这样的业务:将删除的用户信息记录到记录表,再删除用户表中的信息. 可以说是不幸也可以说是幸运的. 在以往遇到这样的业务,我会考虑到各种出现异常或者失败的情况.在删除一张表数据失败的情况,对 ...

  3. 【NET Core】事务TransactionScope

    .NET FrameWork时期: TransactionScope是FCL System.Transactions命名空间下的分布式事务组件,它默认为本地事务,当系统有需要时可以自动提升为分布式事务 ...

  4. 分布式事务TransactionScope所导致几个坑

    记录一下,个人见解,欢迎指正 错误: 1.该伙伴事务管理器已经禁止了它对远程/网络事务的支持. (异常来自 HRESULT:0x8004D025)2.事务已被隐式或显式提交,或已终止3.此操作对该事务 ...

  5. C#轻量级企业事务 - TransactionScope

    using System; using System.Data.SqlClient; using System.Transactions; namespace SomeDBTransaction { ...

  6. .Net高级进阶,在复杂的业务逻辑下,如何以最简练的代码,最直观的编写事务代码?

    本文将通过场景例子演示,来通俗易懂的讲解在复杂的业务逻辑下,如何以最简练的代码,最直观的编写事务代码. 通过一系列优化最终达到两个效果,1.通过代码块来控制事务(分布式事务),2.通过委托优化Tran ...

  7. 事务使用中如何避免误用分布式事务(System.Transactions.TransactionScope)

    1:本地事务DbTransaction和分布式事务TransactionScope的区别: 1.1:System.Data.Common.DbTransaction: 本地事务:这个没什么好说了,就是 ...

  8. 如何避免误用分布式事务(System.Transactions.TransactionScope)

    以下内容来源与:http://www.cyqdata.com/cyq1162/article-detail-54453 1:本地事务DbTransaction和分布式事务TransactionScop ...

  9. 谈谈分布式事务之三: System.Transactions事务详解[下篇]

    在前面一篇给出的Transaction的定义中,信息的读者应该看到了一个叫做DepedentClone的方法.该方法对用于创建基于现有Transaction对 象的“依赖事务(DependentTra ...

随机推荐

  1. Java Spring mvc 操作 Redis 及 Redis 集群

    本文原创,转载请注明:http://www.cnblogs.com/fengzheng/p/5941953.html 关于 Redis 集群搭建可以参考我的另一篇文章 Redis集群搭建与简单使用 R ...

  2. 命令行查看Windows激活信息(win7、win8、win10...)

    使用:Win+ R 组合键,打开运行命令框,复制命令,粘贴后回车. slmgr.vbs -xpr 查询Windows是否永久激活slmgr.vbs -dlv 查询到Windows的激活信息,包括:激活 ...

  3. Tomcat 8熵池阻塞变慢详解(putty)

    原因 Tomcat 7/8都使用org.apache.catalina.util.SessionIdGeneratorBase.createSecureRandom类产生安全随机类SecureRand ...

  4. Android开发学习之路-Android中使用RxJava

    RxJava的核心内容很简单,就是进行异步操作.类似于Handler和AsyncTask的功能,但是在代码结构上不同. RxJava使用了观察者模式和建造者模式中的链式调用(类似于C#的LINQ). ...

  5. SQLite的基本使用

    SQLite 创建表 SQLite 的 CREATE TABLE 语句用于在任何给定的数据库创建一个新表.创建基本表,涉及到命名表.定义列及每一列的数据类型. 语法 CREATE TABLE 语句的基 ...

  6. JavaScript权威设计--事件冒泡,捕获,事件句柄,事件源,事件对象(简要学习笔记十八)

    1.事件冒泡与事件捕获 2.事件与事件句柄   3.事件委托:利用事件的冒泡技术.子元素的事件最终会冒泡到父元素直到跟节点.事件监听会分析从子元素冒泡上来的事件. 事件委托的好处:     1.每个函 ...

  7. C#:浅析结构与类的区别

    一.      结构:值类型,存储在堆栈中,位于计算机的内存逻辑区域中      类   :引用类型,存储在堆中,位于计算机内存的不同逻辑位置   二.      较小的数据使用结构:      将一 ...

  8. heart

    好久没写博客了,不想废话,直接欣赏效果! 点击这里,查看完美效果! 附完整代码: <!doctype html> <html> <head> <meta ch ...

  9. 学习EF之贪懒加载和延迟加载(2)

    通过昨天对EF贪婪加载和延迟加载的学习,不难发现,延迟加载还是很好用的,但是问题也就来了,有的时候我们只需要加载一个实体,不需要和他相关的外部实体,这时候我们来看看EF延迟加载时怎么作用的吧 打开pr ...

  10. C++进程间通信

    # C++进程间通信 # 进程间通讯的四种方式:剪贴板.匿名管道.命名管道和邮槽 ## 剪切板 ## //设置剪切板内容 CString str; this->GetDlgItemText(ID ...