在操作数据库的过程中,为了数据的一致性,我们可以使用Transaction,要么成功的时候全部提交,要么有任何一个操作失败立即全部回滚。不仅仅是在数据库方面,有时候操作其他的内容,比如说对于系统文件的操作,也需要把一些操作组合看做是一个事务。

现在我们看这样一个例子。现在我们需要在计算机的硬盘上创建3个目录A,B,C,要求要么3个全部创建成功,要么一个也不要创建。我们可以把这个看成是一个事务。如果我们自己写代码来操作,可以这样写。

  1. bool createA = false;
  2. bool createB = false;
  3. bool createC = false;
  4. try
  5. {
  6. //这里的操作是创建3个目录
  7. Directory.CreateDirectory("\\A");
  8. createA = true;
  9. Directory.CreateDirectory("\\B");
  10. createB = true;
  11. Directory.CreateDirectory("\\C");
  12. createC = true;
  13. }
  14. catch (System.Exception ex)
  15. {
  16. //这里在捕捉到异常时,根据运行的结果进行回滚
  17. if (createB)
  18. {
  19. Directory.Delete("\\B");
  20. Directory.Delete("\\A");
  21. }
  22. if (!createB && createA)
  23. {
  24. Directory.Delete("\\A");
  25. }
  26. }

但是这里我们是把这3个操作当成一个整体来回滚,及时是简单的创建删除文件夹,我们可以看到catch中的回滚逻辑已经很复杂了。可以想象,如果A,B,C这3步不仅仅是创建目录,还有一些其他的操作,那么回滚的逻辑就非常复杂,此时,我们可以考虑把这一个分成几个小事务,分开回滚。代码可以这样写,这里我们使用了Framework提供的Transactin以及TransactioScope类。

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. //这里就不需要了try catch,因为scope就已经完成了这个功能,
  6. //即当有异常发生向外抛的时候,会尝试跳出这个using代码块,
  7. //CLR会在向代码块外边跑异常之前,分别取调用每个transaction的
  8. //roolback方法,只要rollback中你定义的逻辑没有问题,那么所有
  9. //的已发生的操作就会安全的回滚。
  10. using (var scope = new TransactionScope())
  11. {
  12. var A = new OperationA();
  13. Transaction.Current.EnlistVolatile(A, EnlistmentOptions.None);
  14. A.DoWork();
  15. OperationB B = new OperationB();
  16. Transaction.Current.EnlistVolatile(B, EnlistmentOptions.None);
  17. B.DoWork();
  18. scope.Complete();
  19. }
  20. }
  21. }
  22. }
  23. class OperationA : IEnlistmentNotification
  24. {
  25. private bool _isCommitSucceed = false;
  26. public void Commit(Enlistment enlistment)
  27. {
  28. enlistment.Done();
  29. }
  30. public void DoWork()//这是自定义的方法,不是继承IEnlistmentNotification
  31. {
  32. Directory.CreateDirectory("\\A");
  33. //这里还有一些其他的关于A的复杂操作
  34. _isCommitSucceed = true;
  35. }
  36. public void InDoubt(Enlistment enlistment)
  37. {
  38. enlistment.Done();
  39. }
  40. public void Prepare(PreparingEnlistment preparingEnlistment)
  41. {
  42. preparingEnlistment.Prepared();
  43. }
  44. public void Rollback(Enlistment enlistment)
  45. {
  46. //这里回滚A的一些操作,当然这里的操作逻辑需要你自己来写。
  47. //比如说查看是否创建成功,或者有一些其他的信号标记,通过这些
  48. //标记你来决定是删除目录还是其他的什么回滚操作。
  49. if (_isCommitSucceed)
  50. Directory.Delete("\\A");
  51. enlistment.Done();
  52. }
  53. }
  54. class OperationB : IEnlistmentNotification
  55. {
  56. private bool _isCommitSucceed = false;
  57. public void Commit(Enlistment enlistment)
  58. {
  59. enlistment.Done();
  60. }
  61. public void DoWork()
  62. {
  63. //这里是关于B的一些复杂操作
  64. throw new Exception("test");
  65. //这里依然有一些操作代码,但是我们模拟的是B操作途中抛出异常,所以这里的代码不会执行
  66. }
  67. public void InDoubt(Enlistment enlistment)
  68. {
  69. enlistment.Done();
  70. }
  71. public void Prepare(PreparingEnlistment preparingEnlistment)
  72. {
  73. preparingEnlistment.Prepared();
  74. }
  75. public void Rollback(Enlistment enlistment)
  76. {
  77. if (_isCommitSucceed)
  78. {
  79. //这里回滚B的一些已经存在的操作。
  80. }
  81. enlistment.Done();
  82. }

这里的机制是这样的,可能是scope.Complete()方法中有某种特别的操作,去告诉CLR这次所有的操作都顺利完成了,在跳出这个scope的时候就不用调用那些transaction的rollback方法了。如果没有执行到scope.Complete()方法,那么就会在跳出这个scope代码块的时候调用rollback方法。一般造成这个的原因是在某个transaction的逻辑操作中出现异常,造成从此次直接抛出异常跳出这个代码块,没有机会执行下边的代码。可以看出这里的重点也是写rollback的逻辑,但是相对于原来的catch中的逻辑,这里分开为多个小的逻辑,相对来说容易了很多。

这只是个人写的一种使用回滚的逻辑。在使用IEnlistmentNotification的时候,也有人把业务逻辑写入到Commit中。如果想真正理解transaction回滚的机制,建议深入理解一下TransactionScope与Transactiond的实现机制。

关于使用Transaction对于非数据库事务的操作的更多相关文章

  1. mysql数据库事务的操作与理解

    --------------------事务----------------------------------------------查询mysql事务隔离级别1.查看当前会话隔离级别select ...

  2. Mysql数据库事务的四大特性:

    什么是事务? 事务Transaction,是指作为一个基本工作单元执行的一系列SQL语句的操作,要么完全地执行,要么完全地都不执行.为什么要使用事务:保证对数据操作的完整性和准确性.1,原子性:一个事 ...

  3. mysql事务之一:MySQL数据库事务隔离级别(Transaction Isolation Level)及锁的实现原理

    一.数据库隔离级别 数据库隔离级别有四种,应用<高性能mysql>一书中的说明: 然后说说修改事务隔离级别的方法: 1.全局修改,修改mysql.ini配置文件,在最后加上 1 #可选参数 ...

  4. transaction 数据库事务 roolback 回滚

    事务是恢复和并发控制的基本单位 https://baike.baidu.com/item/数据库事务/9744607 事务有三种模型: 1.隐式事务是指每一条数据操作语句都自动地成为一个事务,事务的开 ...

  5. 【转】数据库事务ACID以及事务隔离

      本篇讲诉数据库中事务的四大特性(ACID),并且将会详细地说明事务的隔离级别. 如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: ⑴ 原子性(Atomicity) 原子性是指 ...

  6. Django数据库--事务及事务回滚

    数据库的读写操作中,事务在保证数据的安全性和一致性方面起着关键的作用,而回滚正是这里面的核心操作.Django的ORM在事务方面也提供了不少的API.有事务出错的整体回滚操作,也有基于保存点的部分回滚 ...

  7. 理解MySQL数据库事务

    1. 什么是事务处理? 事务处理是一种机制,它是用来管理必须成批执行的mysql操作.来保证数据库不完整的操作结果. 2. 为什么要使用事务处理? 在使用mysql操作数据的过程中,如果只是简单的中小 ...

  8. 数据库事务的四大特性以及事务的隔离级别(mysql)

      本篇讲诉数据库中事务的四大特性(ACID),并且将会详细地说明事务的隔离级别. 如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: ⑴ 原子性(Atomicity) 原子性是指 ...

  9. 数据库事务的四大特性以及事务的隔离级别-与-Spring事务传播机制&隔离级别

    数据库事务的四大特性以及事务的隔离级别   本篇讲诉数据库中事务的四大特性(ACID),并且将会详细地说明事务的隔离级别. 如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: ⑴ ...

随机推荐

  1. for-in遍历json数据

    1.for遍历json数据 ','fun':'前端开发'} for(var attr in json){ alert(json[attr]) //遍历json属性的数据 alert(json['nam ...

  2. 基于CentOS与VmwareStation10搭建Oracle11G RAC 64集群环境:2.搭建环境-2.4. 安装JDK

    2.4.安装JDK 2.4.1.准备JDK 在百度搜索:JDK下载 2.4.2.上传JDK put E:\软件安装文件\jdk-8u11-linux-x64.rpm /home/linuxrac1/D ...

  3. SQL语句构建器类

    问题 Java程序员面对的最痛苦的事情之一就是在Java代码中嵌入SQL语句.这么来做通常是由于SQL语句需要动态来生成-否则可以将它们放到外部文件或者存储过程中.正如你已经看到的那样,MyBatis ...

  4. 7、NFC技术:让Android自动运行程序

    用于描述NDEF格式数据的两个重要的类 NdefMessage:描述NDEF格式的信息 NdefRecord:描述NDEF信息的一个信息段  NdefMessage和NdefRecord是Androi ...

  5. echart图表控件配置入门(二)常用图表数据动态绑定

    上一节 <echart图表控件配置入门(一)>介绍了echarts图表控件的入门配置,使开发人员可以快速搭建出一个静态的图表.但是在实际开发过程这还是不够的,不可能所有的图表控件都是静态数 ...

  6. echart图表控件配置入门(一)

    现在主流的web图表控件主要有hightchart.fusionchart.echart: echart作为百度前端部门近期推出的一个基于html5的免费图表控件,以其丰富图表类型和良好的兼容性速度得 ...

  7. CentOS下挂在NTFS分区

    本文参考自http://www.cnblogs.com/gbyukg/archive/2011/11/02/2232343.html centos下想访问NTFS分区,现在普遍的方法是利用ntfs-3 ...

  8. Camera拍照声设定

    在某些国家(比如Japan),为了防止偷拍,强制拍照声是需要从Speaker出来的(即使插入耳机的情况下). 实现该功能比较简单的方法就是将拍照声类型设置为Ringtone 或 Alarm 或 Not ...

  9. [Android][Audio] audio_policy.conf文件分析

    不同的Android产品在音频的设计上通常是存在差异的,而这些差异可以同过Audio的配置文件audio_policy.conf来获得.在Android系统中音频配置文件存放路径有两处,存放地址可以从 ...

  10. sudo 权限问题

    窝里个去,不使用sudo吧rvm requirements执行不成功.加上sudo吧rvm requirements调用的brew install又不行.好吧,就按上面说的将brew转换到root模式 ...