问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

关于Spring@Transactional 的事务控制问题

发布网友 发布时间:2022-04-07 19:41

我来回答

2个回答

懂视网 时间:2022-04-08 00:02

  • bool createB = false;  
  • bool createC = false;  
  •   
  • try  
  • {  
  •     //这里的操作是创建3个目录  
  •     Directory.CreateDirectory("\A");  
  •     createA = true;  
  •     Directory.CreateDirectory("\B");  
  •     createB = true;  
  •     Directory.CreateDirectory("\C");  
  •     createC = true;  
  • }  
  • catch (System.Exception ex)  
  • {  
  •     //这里在捕捉到异常时,根据运行的结果进行回滚  
  •     if (createB)  
  •     {  
  •         Directory.Delete("\B");  
  •         Directory.Delete("\A");  
  •     }  
  •     if (!createB && createA)  
  •     {  
  •         Directory.Delete("\A");  
  •     }  
  • }  


  •  

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

     

    [csharp] view plaincopy技术分享技术分享  
    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.   
    16.                 OperationB B = new OperationB();  
    17.                 Transaction.Current.EnlistVolatile(B, EnlistmentOptions.None);  
    18.                 B.DoWork();  
    19.                 scope.Complete();  
    20.             }  
    21.         }  
    22.   
    23.   
    24.     }  
    25. }  
    26.   
    27. class OperationA : IEnlistmentNotification  
    28. {  
    29.     private bool _isCommitSucceed = false;  
    30.   
    31.     public void Commit(Enlistment enlistment)  
    32.     {  
    33.         enlistment.Done();  
    34.     }  
    35.   
    36.     public void DoWork()//这是自定义的方法,不是继承IEnlistmentNotification  
    37.     {  
    38.         Directory.CreateDirectory("\A");  
    39.         //这里还有一些其他的关于A的复杂操作  
    40.         _isCommitSucceed = true;  
    41.     }  
    42.   
    43.     public void InDoubt(Enlistment enlistment)  
    44.     {  
    45.         enlistment.Done();  
    46.     }  
    47.     public void Prepare(PreparingEnlistment preparingEnlistment)  
    48.     {  
    49.         preparingEnlistment.Prepared();  
    50.     }  
    51.     public void Rollback(Enlistment enlistment)  
    52.     {  
    53.         //这里回滚A的一些操作,当然这里的操作逻辑需要你自己来写。  
    54.         //比如说查看是否创建成功,或者有一些其他的信号标记,通过这些  
    55.         //标记你来决定是删除目录还是其他的什么回滚操作。  
    56.         if (_isCommitSucceed)  
    57.             Directory.Delete("\A");  
    58.         enlistment.Done();  
    59.     }  
    60. }  
    61.   
    62. class OperationB : IEnlistmentNotification  
    63. {  
    64.     private bool _isCommitSucceed = false;  
    65.   
    66.     public void Commit(Enlistment enlistment)  
    67.     {  
    68.         enlistment.Done();  
    69.     }  
    70.   
    71.     public void DoWork()  
    72.     {  
    73.         //这里是关于B的一些复杂操作  
    74.         throw new Exception("test");  
    75.         //这里依然有一些操作代码,但是我们模拟的是B操作途中抛出异常,所以这里的代码不会执行  
    76.     }  
    77.   
    78.     public void InDoubt(Enlistment enlistment)  
    79.     {  
    80.         enlistment.Done();  
    81.     }  
    82.     public void Prepare(PreparingEnlistment preparingEnlistment)  
    83.     {  
    84.         preparingEnlistment.Prepared();  
    85.     }  
    86.     public void Rollback(Enlistment enlistment)  
    87.     {  
    88.         if (_isCommitSucceed)  
    89.         {  
    90.             //这里回滚B的一些已经存在的操作。  
    91.         }  
    92.         enlistment.Done();  
    93.     }  


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

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

    关于使用Transaction对于非数据库事务的操作

    标签:

    热心网友 时间:2022-04-07 21:10

    看下下面的代码,不知道能不能解决你的问题:
    <beans>
    <bean id="dataSource"
    class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="driverClassName">
    <value>org.gjt.mm.mysql.Driver</value>
    </property>
    <property name="url">
    <value>jdbc:mysql://localhost/sample</value>
    </property>
    <property name="username">
    <value>user</value>
    </property>
    <property name="password">
    <value>mypass</value>
    </property>
    </bean>
    <bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTr
    ansactionManager">
    <property name="dataSource">
    <ref local="dataSource" />
    </property>
    </bean>
    <bean id="userDAO" class="net.xiaxin..UserDAO">
    <property name="dataSource">
    <ref local="dataSource" />
    </property>
    </bean>
    <bean id="userDAOProxy"
    class="org.springframework.transaction.interceptor.Tran
    sactionProxyFactoryBean">
    <property name="transactionManager">
    <ref bean="transactionManager" />
    </property>
    <property name="target">
    <ref local="userDAO" />
    </property>
    <property name="transactionAttributes">
    <props>
    <prop key="insert*">PROPAGATION_REQUIRED</prop>
    <prop key="get*">
    PROPAGATION_REQUIRED,readOnly
    </prop>
    </props>
    </property>
    </bean>
    </beans>

    配置中包含了dataSource,transactionManager 等资源定义。这些资源都为
    一个名为userDAOProxy 的TransactionProxyFactoryBean 服务, 而
    userDAOProxy 则对包含实际数据逻辑的userDAO进行了事务性封装。
    可以看到,在userDAOProxy 的"transactionAttributes"属性中,我们定义了
    针对userDAO 的事务策略,即将所有名称以insert 开始的方法(如
    UserDAO.insertUser方法)纳入事务管理范围。如果此方法中抛出异常,则Spring
    将当前事务回滚,如果方法正常结束,则提交事务。
    而对所有名称以get 开始的方法(如UserDAO.getUser 方法)则以只读的事务
    处理机制进行处理。(设为只读型事务,可以使持久层尝试对数据操作进行优化,如对
    于只读事务Hibernate将不执行flush操作,而某些数据库连接池和JDBC 驱动也对
    只读型操作进行了特别优化。)
    声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
    湖北哪些学校有专升本 湖北哪些学校可以报专升本 华为mate7会不会卡 中央集权的本质 秦朝中央集权的实质是什么 秦朝建立专制主义中央集权制度的本质特征是 A改王为皇帝 B建立中央官制... 想生个女儿怎么备孕 怎样备孕生女孩7个方法 备孕怎样做才能生女孩 天津市国税局公务员面试成绩去哪儿查? 炸好的烧茄子放在冷藏室里五天了能吃吗? 师傅们!为什么我炸硬烧茄子的时候!茄子总粘在一起呢!而且炸的还不硬! 老房子加装电梯可以提取公积金吗? 老房子装修,可以把住房公积金全部取出来吗,又需要什 装修房屋可以提取公积金吗 和射手女最配的是哪个星座? 黑暗光年电脑版下载安装教程 和射手女相配的星座 射手座女生和什么座最配 电脑版店宝宝怎么下载安装? 射手女与哪个星座男最配、最搭? 战地风云电脑版下载安装教程 电脑版怎么安装 求射手座(女)和那个星座最配~~越详细越好!!!最好是加上出生日期_百度知 ... 现代战争5电脑版下载安装教程 电脑版怎么安装 射手女和什么星座最匹配? 梦见飞机实然低飞伸手一只手带我起飞了? 射手座的女生适合什么星座的男孩子? 梦见自己飞机飞的很低,自己把飞机撞了,还把飞机推到沟里去了,自己跳... 可行性分析报告的介绍 射手女和什么星座最配? 在国外承认的中国211大学有哪些? 我国境内首个境外高校独立办学项目什么时候开始招生? 我国境内首个境外高校独立办学项目落户哪里? 世界高水平大学和中国一流大学哪个好世界高水平大学和中国一流大学哪个好_百度问一问 中国一流大学和世界高水平大学有什么区别? 国家建设高水平大学公派研究生项目的46所高校 有哪些 世界高水平大学和中国一流大学哪个好世界高水平大学和中国一流大学哪个好_百度问一问 什么是高水平大学 华为手机怎么连上网却不能用 财神前的长明灯是需要24小时开着还是只用白天开着 供奉财神爷的灯用总开着吗 财神供桌能放莲花灯 财神爷供桌上的蜡烛灯总亮着吗? 家里供奉财神爷的灯晚上用关吗 供财神点灯吗 小年怎么给财神爷上供品 财神爷的香炉和供果应该怎么摆放正确? 财神爷点什么颜色的灯好十字绣 用完的供灯怎么处理 供财神用什么供品