您的位置:首页 > 编程语言 > Java开发

学习笔记-------spring 事务控制

2017-08-31 11:39 351 查看


Spring Java 事务原理与应用

事务控制有两种,一种是配置相应的方法,一种是通过注解@Transaction,可以在配置文件中都配置也可以有选择的配置。

数据表需要时InnoDB

       一、什么是Java事务

    事务必须服从ISO/IEC所制定的ACID原则。ACID是原子性(atomicity)、一致性(consistency)、隔离性 (isolation)和持久性(durability)的缩写。事务的原子性表示事务执行过程中的任何失败都将导致事务所做的任何修改失效。一致性表示 当事务执行失败时,所有被该事务影响的数据都应该恢复到事务执行前的状态。隔离性表示在事务执行过程中对数据的修改,在事务提交之前对其他事务不可见。持久性表示已提交的数据在事务执行失败时,数据的状态都应该正确。

      二、为什么需要Java事务
    事务是为解决数据安全操作提出的,事务控制实际上就是控制数据的安全访问。举一个简单例子:比如银行转帐业务,账户A要将自己账户上的1000元转到B账 户下面,A账户余额首先要减去1000元,然后B账户要增加1000元。假如在中间网络出现了问题,A账户减去1000元已经结束,B因为网络中断而操作 失败,那么整个业务失败,必须做出控制,要求A账户转帐业务撤销。这才能保证业务的正确性,完成这个操作就需要事务,将A账户资金减少和B账户资金增加方
到一个事务里面,要么全部执行成功,要么操作全部撤销,这样就保持了数据的安全性。

     三、Java事务的类型
    Java事务的类型有三种:JDBC事务、JTA(Java Transaction API)事务、容器事务。

     1、JDBC事务
    JDBC 事务是用 Connection 对象控制的。JDBC Connection 接口( java.sql.Connection )提供了两种事务模式:自动提交和手工提交。 java.sql.Connection 提供了以下控制事务的方法:
public void setAutoCommit(boolean)

public boolean getAutoCommit()

public void commit()

public void rollback()
    使用 JDBC 事务界定时,您可以将多个 SQL 语句结合到一个事务中。JDBC 事务的一个缺点是事务的范围局限于一个数据库连接。一个 JDBC 事务不能跨越多个数据库。

      2、JTA(Java Transaction API)事务
    JTA是一种高层的,与实现无关的,与协议无关的API,应用程序和应用服务器可以使用JTA来访问事务。
    JTA允许应用程序执行分布式事务处理——在两个或多个网络计算机资源上访问并且更新数据,这些数据可以分布在多个数据库上。JDBC驱动程序的JTA支持极大地增强了数据访问能力。
    如果计划用 JTA 界定事务,那么就需要有一个实现 javax.sql.XADataSource 、 javax.sql.XAConnection 和 javax.sql.XAResource 接口的 JDBC 驱动程序。一个实现了这些接口的驱动程序将可以参与 JTA 事务。一个 XADataSource 对象就是一个 XAConnection 对象的工厂。 XAConnection s 是参与 JTA
事务的 JDBC 连接。
    您将需要用应用服务器的管理工具设置 XADataSource .从应用服务器和 JDBC 驱动程序的文档中可以了解到相关的指导。
     J2EE应用程序用 JNDI 查询数据源。一旦应用程序找到了数据源对象,它就调用 javax.sql.DataSource.getConnection() 以获得到数据库的连接。
    XA 连接与非 XA 连接不同。一定要记住 XA 连接参与了 JTA 事务。这意味着 XA 连接不支持 JDBC 的自动提交功能。同时,应用程序一定不要对 XA 连接调用 java.sql.Connection.commit() 或者 java.sql.Connection.rollback()
.(这些是自动提交的)
    相反,应用程序应该使用 UserTransaction.begin()、 UserTransaction.commit() 和 UserTransaction.rollback() .

    3、容器事务
    容器事务主要是J2EE应用服务器提供的,容器事务大多是基于JTA完成,这是一个基于JNDI的,相当复杂的API实现。相对编码实现JTA事务管理, 我们可以通过EJB容器提供的容器事务管理机制(CMT)完成同一个功能,这项功能由J2EE应用服务器提供。这使得我们可以简单的指定将哪个方法加入事 务,一旦指定,容器将负责事务管理任务。这是我们土建的解决方式,因为通过这种方式我们可以将事务代码排除在逻辑编码之外,同时将所有困难交给J2EE容
器去解决。使用EJB CMT的另外一个好处就是程序员无需关心JTA API的编码,不过,理论上我们必须使用EJB.
  

     四、三种Java事务差异
    1、JDBC事务控制的局限性在一个数据库连接内,但是其使用简单。
    2、JTA事务的功能强大,事务可以跨越多个数据库或多个DAO,使用也比较复杂。
    3、容器事务,主要指的是J2EE应用服务器提供的事务管理,局限于EJB应用使用。

自动提交事务:每条单独的语句都是一个事务。每个语句后都隐含一个commit。 (默认)

 

显式事务:以begin transaction显示开始,以commit或rollback结束。

隐式事务:当连接以隐式事务模式进行操作时,sql server数据库引擎实例将在提交或回滚当前事务后自动启动新事务。无须描述事物的开始,只需提交或回滚每个事务。但每个事务仍以commit或rollback显式结束。连接将隐性事务模式设置为打开之后,当数据库引擎实例首次执行下列任何语句时,都会自动启动一个隐式事务:alter
table,insert,create,open ,delete,revoke ,drop,select, fetch ,truncate table,grant,update在发出commit或rollback语句之前,该事务将一直保持有效。在第一个事务被提交或回滚之后,下次当连接执行以上任何语句时,数据库引擎实例都将自动启动一个新事务。该实例将不断地生成隐性事务链,直到隐性事务模式关闭为止。

   五、事务并发处理可能引起的问题
脏读(dirty read) 一个事务读取了另一个事务尚未提交的数据,
不可重复读(non-repeatable read) 一个事务的操作导致另一个事务前后两次读取到不同的数据
幻读(phantom read) 一个事务的操作导致另一个事务前后两次查询的结果数据量不同。
举例:
事务A、B并发执行时,
当A事务update后,B事务select读取到A尚未提交的数据,此时A事务rollback,则B读到的数据是无效的"脏"数据。
当B事务select读取数据后,A事务update操作更改B事务select到的数据,此时B事务再次读去该数据,发现前后两次的数据不一样。
当B事务select读取数据后,A事务insert或delete了一条满足A事务的select条件的记录,此时B事务再次select,发现查询到前次不存在的记录("幻影"),或者前次的某个记录不见了。

     六、保存点(SavePoint)
JDBC定义了SavePoint接口,提供在一个更细粒度的事务控制机制。当设置了一个保存点后,可以rollback到该保存点处的状态,而不是rollback整个事务。
Connection接口的setSavepoint和releaseSavepoint方法可以设置和释放保存点。


Spring 之注解事务 @Transactional
@Transactional

spring 事务注解

默认遇到throw new RuntimeException("...");会回滚
需要捕获的throw new Exception("...");不会回滚

(默认spring事务只在发生未被捕获的 runtimeexcetpion时才回滚。  
   spring aop  异常捕获原理:被拦截的方法需显式抛出异常,并不能经任何处理,这样aop代理才能捕获到方法的异常,才能进行回滚,默认情况下aop只捕获runtimeexception的异常,但可以通过  
    
配置来捕获特定的异常并回滚  
  换句话说在service的方法中不使用try catch 或者在catch中最后加上throw new runtimeexcetpion(),这样程序异常时才能被aop捕获进而回滚,throw new XXX 其中XXX异常只要是runtimeexception的子类都可以。
  解决方案: 
  方案1.例如service层处理事务,那么service中的方法中不做异常捕获,或者在catch语句中最后增加throw new RuntimeException()语句,以便让aop捕获异常再去回滚,并且在service上层(webservice客户端,view层action)要继续捕获这个异常并处理
  方案2.在service层方法的catch语句中增加:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();语句,手动回滚,这样上层就无需去处理异常(现在项目的做法))

// 指定回滚

@Transactional(rollbackFor=Exception.class) 

    public void methodName() {
       // 不会回滚

       throw new Exception("...");

    } 
//指定不回滚

@Transactional(noRollbackFor=Exception.class)

    public ItimDaoImpl getItemDaoImpl() {
        // 会回滚

        throw new RuntimeException("注释");

    } 

    // 如果有事务,那么加入事务,没有的话新建一个(不写的情况下)会导致一个失败,所有加入事务中的service都回滚。适用于多个操作一个失败全部回滚。

    @Transactional(propagation=Propagation.REQUIRED) 
    // 容器不为这个方法开启事务

    @Transactional(propagation=Propagation.NOT_SUPPORTED)

    // 不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务

    @Transactional(propagation=Propagation.REQUIRES_NEW) 

    // 必须在一个已有的事务中执行,否则抛出异常

    @Transactional(propagation=Propagation.MANDATORY)

    // 必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)

    @Transactional(propagation=Propagation.NEVER) 

    // 如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务.

    @Transactional(propagation=Propagation.SUPPORTS) 

    
    /*
    public void methodName(){
       // 本类的修改方法 1
       update();
       // 调用其他类的修改方法
       otherBean.update();
       // 本类的修改方法 2
       update();
    }
    other失败了不会影响 本类的修改提交成功
    本类update的失败,other也失败
    */

@Transactional(propagation=Propagation.NESTED) 
// readOnly=true只读,不能更新,删除 

@Transactional (propagation = Propagation.REQUIRED,readOnly=true) 
// 设置超时时间

@Transactional (propagation = Propagation.REQUIRED,timeout=30)
// 设置数据库隔离级别

@Transactional (propagation = Propagation.REQUIRED,isolation=Isolation.DEFAULT)


事务的xml配置说明

<!--事务相关控制-->  
 <!-- 开启事务支持 -->
<!--<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>  
</bean>    

<!--把事务控制在Service层,配置事务切入点,以及把事务切入点和事务属性关联起来-->    
<aop:config expose-proxy="true">       
<aop:pointcut id="txPointcut" expression="execution(* org.spring.service..*.*(..))" />    
<aop:advisor id="txAdvisor" advice-ref="txAdvice" pointcut-ref="txPointcut"  />    
</aop:config>

事务控制通过2中方式
1、这里需要注意,这种事务配置是自动识别方法来完成事务控制

<!-- 事务增强 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">    
<tx:attributes>  
<tx:method name="getAcceptValue" propagation="REQUIRES_NEW"/>  
<tx:method name="insert*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>
<tx:method name="add*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>       
<tx:method name="save*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>
<tx:method name="create*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>           
<tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>     
<tx:method name="modify*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>    
<tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="Exception"/>   
<tx:method name="find*"  propagation="SUPPORTS" read-only="false" rollback-for="Exception"/>   
<tx:method name="select*" propagation="SUPPORTS" read-only="false" rollback-for="Exception"/> 
<tx:method name="qry*" propagation="SUPPORTS" read-only="false" rollback-for="Exception"/> 
<tx:method name="query*" propagation="SUPPORTS" read-only="false" rollback-for="Exception"/> 
<tx:method name="*"/>
</tx:attributes>    
</tx:advice>

事务增强以后,service层出现以配置文件中类似开头(insert\add\save\...)的方法都会自动增加事务,出现异常会自动回滚。

在实际写代码的时候,如果异常被catch住而且没有向上抛出的话,事务就无法回滚。因为程序不知道是否发省了异常。如果控制事务,尽量出现异常要抛出。

Spring事务管理是根据异常来进行回滚操作; Spring与Mybatis整合时,虽然在Service方法中并没有check异常,但是如果数据库有异常发生,默认会进行事务回滚。
Spring 如果不添加rollbackFor等属性,Spring碰到Unchecked Exceptions都会回滚,不仅是RuntimeException,也包括Error。 如果在事务方法中捕获异常并进行处理,一定要继续抛出异常并在Spring事务管理中进行rollbak-for配置。

2、利用@Transaction注解方式进行事务控制

<!-- 支持 @Transactional 标记 -->
<tx:annotation-driven />

事务管理方式

spring支持编程式事务管理和声明式事务管理两种方式。

编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。

声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。

显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持。和编程式事务相比,声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。

声明式事务管理也有两种常用的方式,一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。

自动提交(AutoCommit)与连接关闭时的是否自动提交

自动提交

默认情况下,数据库处于自动提交模式。每一条语句处于一个单独的事务中,在这条语句执行完毕时,如果执行成功则隐式的提交事务,如果

执行失败则隐式的回滚事务。

对于正常的事务管理,是一组相关的操作处于一个事务之中,因此必须关闭数据库的自动提交模式。不过,这个我们不用担心,spring会将底层连接的自动提交特性设置为false。

org/springframework/jdbc/datasource/DataSourceTransactionManager.java

1 // switch to manual commit if necessary. this is very expensive in some jdbc drivers,
2 // so we don't want to do it unnecessarily (for example if we've explicitly
3 // configured the connection pool to set it already).
4 if (con.getautocommit()) {
5     txobject.setmustrestoreautocommit(true);
6     if (logger.isdebugenabled()) {
7         logger.debug("switching jdbc connection [" + con + "] to manual commit");
8     }
9     con.setautocommit(false);
10 }


有些数据连接池提供了关闭事务自动提交的设置,最好在设置连接池时就将其关闭。但C3P0没有提供这一特性,只能依靠spring来设置。

因为JDBC规范规定,当连接对象建立时应该处于自动提交模式,这是跨DBMS的缺省值,如果需要,必须显式的关闭自动提交。C3P0遵守这一规范,让客户代码来显式的设置需要的提交模式。

连接关闭时的是否自动提交

当一个连接关闭时,如果有未提交的事务应该如何处理?JDBC规范没有提及,C3P0默认的策略是回滚任何未提交的事务。这是一个正确的策略,但JDBC驱动提供商之间对此问题并没有达成一致。

C3P0的autoCommitOnClose属性默认是false,没有十分必要不要动它。或者可以显式的设置此属性为false,这样会更明确。

基于注解的声明式事务管理配置

spring-servlet.xml

1 <!-- transaction support-->
2 <!-- PlatformTransactionMnager -->
3 <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
4     <property name="dataSource" ref="dataSource" />
5 </bean>
6 <!-- enable transaction annotation support -->
7 <tx:annotation-driven transaction-manager="txManager" />


还要在spring-servlet.xml中添加tx名字空间

1 ...
2     xmlns:tx="http://www.springframework.org/schema/tx"
3     xmlns:aop="http://www.springframework.org/schema/aop"
4     xsi:schemaLocation="
5     ...
6
7 http://www.springframework.org/schema/tx 8
9
10 http://www.springframework.org/schema/tx/spring-tx.xsd 11
12     ...


MyBatis自动参与到spring事务管理中,无需额外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的数据源与DataSourceTransactionManager引用的数据源一致即可,否则事务管理会不起作用。

另外需要下载依赖包aopalliance.jar放置到WEB-INF/lib目录下。否则spring初始化时会报异常

java.lang.NoClassDefFoundError: org/aopalliance/intercept/MethodInterceptor

spring事务特性

spring所有的事务管理策略类都继承自org.springframework.transaction.PlatformTransactionManager接口

1 public interface PlatformTransactionManager {
2
3   TransactionStatus getTransaction(TransactionDefinition definition)
4     throws TransactionException;
5
6   void commit(TransactionStatus status) throws TransactionException;
7
8   void rollback(TransactionStatus status) throws TransactionException;
9 }


其中TransactionDefinition接口定义以下特性:

事务隔离级别

隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:
TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。比如PostgreSQL实际上并没有此级别。
TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。
TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

事务传播行为

所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:
TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

事务超时

所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。

默认设置为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那么就是none,没有超时限制。

事务只读属性

只读事务用于客户代码只读但不修改数据的情形,只读事务用于特定情景下的优化,比如使用Hibernate的时候。

默认为读写事务。

spring事务回滚规则

指示spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常。spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务。

默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常则不会导致事务回滚。

可以明确的配置在抛出那些异常时回滚事务,包括checked异常。也可以明确定义那些异常抛出时不回滚事务。

还可以编程性的通过setRollbackOnly()方法来指示一个事务必须回滚,在调用完setRollbackOnly()后你所能执行的唯一操作就是回滚。

@Transactional注解

@Transactional属性
 
属性类型描述
valueString可选的限定描述符,指定使用的事务管理器
propagationenum: Propagation可选的事务传播行为设置
isolationenum: Isolation可选的事务隔离级别设置
readOnlyboolean读写或只读事务,默认读写
timeoutint (in seconds granularity)事务超时时间设置
rollbackForClass对象数组,必须继承自Throwable导致事务回滚的异常类数组
rollbackForClassName类名数组,必须继承自Throwable导致事务回滚的异常类名字数组
noRollbackForClass对象数组,必须继承自Throwable不会导致事务回滚的异常类数组
noRollbackForClassName类名数组,必须继承自Throwable不会导致事务回滚的异常类名字数组
 

用法

@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。

虽然 @Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。

默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰。

1 @Transactional(readOnly = true)
2 public class DefaultFooService implements FooService {
3
4   public Foo getFoo(String fooName) {
5     // do something
6   }
7
8   // these settings have precedence for this method
9   //方法上注解属性会覆盖类注解上的相同属性
10   @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
11   public void updateFoo(Foo foo) {
12     // do something
13   }
14 }


 

嵌套事务回滚说明

对于嵌套事务。
1.外部起事务,内部起事务,内外都有Try Catch
内部出错:如果内部事务出错,内部和外部事物全部回滚,外部回滚之前的操作全部不存在,但是之后的操作继续执行。
外部出错:如果外部事物出错,内部和外部事物全部回滚,外部回滚之前的操作全部不存在,但是之后的操作继续执行。
注:如果内部的事务不起事务名称,内部如果出错,将会回滚掉会话中的全部事务,而且报异常。

2.外部起事务,内部起事务,内部没有Try Catch
内部出错:如果内部事务出错,内部和外部事物全部回滚,外部回滚之前的操作全部不存在,但是之后的操作继续执行。
外部出错:如果外部事务出错,内部和外部事物全部回滚,外部回滚之前的操作全部不存在,但是之后的操作继续执行。

------------------------------------------------------------------------------------------------------------

3.外部起事务,内部不起事务,但有Try Catch。
内部出错:外部事物正常提交,外部事物不会进入ROLLBACK,内部出错之后的记录也会正常执行。内部操作中,Try部分在错误出现之前的操作正常,Try部分在操作之后的操作不执行,然后进入Catch块中执行操作。
外部出错:内部和外部事物全部回滚,外部回滚之前的操作全部不存在,但是之后的操作继续执行。

4.外部起事务,内部不起事务,但没有Try Catch.
内部出错:如果内部事务出错,内部和外部事物全部回滚,外部回滚之前的操作全部不存在,但是之后的操作继续执行。
外部出错:如果外部事务出错,内部和外部事物全部回滚,外部回滚之前的操作全部不存在,但是之后的操作继续执行。

------------------------------------------------------------------------------------------------------------

5.外部不起事务,内部起事务,但有Try Catch.
内部出错:外部操作被正常执行,内部ROLLBACK操作前全部回滚,之后的操作正常执行。
外部出错:出错操作之前的操作不会回滚,出错之后的操作不执行,跳入Catch块中,内部事务不会回滚。

6.外部不起事务,内部起事务,但没有Try Catch.
内部出错:外部操作被正常执行,内部ROLLBACK操作前全部回滚。由于没有catch块,所以外部操作全部执行。
外部出错:内部事务正常提交,外部只有当条记录失败,其他操作正常执行,但是有严重错误报出来。

-------------------------------------------------------

对于事务保存点

事务保存点只有SAVE和ROLLBACK操作,当外部调用内部保存点,内部出现问题不影响外部事务,外部操作正常执行。当外部操作出现问题时,内部所有操作都回滚掉。

如:外部起事务,内部起保存点,内外都有Try Catch

内部出错:外部操作正常,不进入Catch,内部事务回滚到保存点,之后的继续执行。

外部出错:如果外部事物在保存点之前出现异常,那么外部和内部所有操作回滚。如果外部事物在保存点之前出现异常,由于保存点已经提交了事务,导致外部rollback找不到对应的事务点。

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring 事务