一、事务的传播行为propagation

事务的第一个方面是传播行为(propagation /,prɒpə'ɡeɪʃən/ behavior)。
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。
规定了事务方法和事务方法发生嵌套调用时事务如何进行传播
例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。

Spring定义了七种传播行为:

spring Transactional 传播行为使用场景 spring传播事务的方式_xml

propagtion_nested:

嵌套的事务可以独立于当前事务进行单独地提交或回滚。
如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。
注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌
套事务

事务传播行为失效的情况

spring事务是基于代理来实现的,所以:
(1)private、final、static 方法无法被代理,所以添加事务无效
(2)当绕过代理对象, 直接调用添加事务管理的方法时, 事务管理将无法生效。比如直接new出的对
象。
(3)在同一个类下,有2个方法,A、B,A没有事务,B有事务,但是A调用B时,方法B被标记的事务
无效。 究其原因,因为此类的调用对象为代理对象,代理方法A调用真正的被代理方法A后,在被代理
方法A中才会去调用方法B,此时this对象为被代理的对象,所以是不会通知到代理对象,也就变成了第
二种情况,绕过了代理对象。所以无效

二、Spring XML配置声明事务

在Spring事务配置时,不同的数据源dataSource对应不同的事务管理器TransactionManager

spring Transactional 传播行为使用场景 spring传播事务的方式_xml_02

(1) TransactionManager

在不同平台,操作事务的代码各不相同,因此spring提供了一个 TransactionManager 接口:

  • DateSourceTransactionManager 用于 JDBC 的事务管理
  • HibernateTransactionManager 用于 Hibernate 的事务管理

(2) 在pom.xml中添加依赖

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.13</version>
</dependency>

(3) 在spring.xml中添加tx命名空间

xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd

(4) 在spring.xml中添加事务相关配置

<!--声明式事务-->
<!--1.创建事务管理器对象-->
<bean id="mytx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="ds"></property>
</bean>
<!--2.指定哪些方法需要进行事务管理-->
<tx:advice id="myad" transaction-manager="mytx">
    <tx:attributes>
        <tx:method name="insert*" propagation="REQUIRED"/>
        <tx:method name="update*" propagation="REQUIRED"/>
        <tx:method name="delete"  propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>
<!--3.使用面向切面的思想指定哪层需要事务管理,事务添加在service层最合理-->
<aop:config>
    <aop:pointcut id="mypc" expression="execution(* com.xzk.dao.*.*(..))"></aop:pointcut>
    <aop:advisor advice-ref="myad" pointcut-ref="mypc"></aop:advisor>
</aop:config>

三、使用注解方式添加事务

(1) 添加tx命名空间

xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd

(2) 配置注解

注意:在默认情况中,transaction-manager属性会自动使用名为 “transactionManager” 的事务管理器。所以,如果用户将事务管理器的id定义为 transactionManager , 则可以进一步将配置简化。

<!--注解事务-->
<!--1.创建事务管理器对象-->
<bean id="mytx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="ds"></property>
</bean>
<!--2.启用注解事务-->
<tx:annotation-driven transaction-manager="mytx"></tx:annotation-driven>
</beans>

(3) 使用@Transactional注解

@Transactional //对业务类进行事务增强的标注 adviced
@Service("accountService")
public class AccountServiceImpl implements AccountService {}

(4) @Transactional其他方面介绍

  • 关于@Transactional的属性
@Transactional默认的属性:
 * 事务传播行为: PROPAGATION_REQUIRED.
 * 事务隔离级别: ISOLATION_DEFAULT.
 * 读写事务属性:读/写事务.
 * 超时时间:依赖于底层的事务系统默认值
 * 回滚设置:任何运行期异常引发回滚,任何检查型异常不会引发回滚.
  • 默认值可能适应大部分情况,但是我们依然可以可以自己设定属性,具体属性表如下:

spring Transactional 传播行为使用场景 spring传播事务的方式_事务_03

  • 在何处标注@Transactional注解?
@Transactional注解可以直接用于接口定义和接口方法,类定义和类的public方法上

 但Spring建议在业务实现类(ServiceImpl)上使用@Transactional注解
 
 当然也可以添加到业务接口上,但是这样会留下一些容易被忽视的隐患,因为注解不能被继承,所以业务接口中标注的@Transactional注解不会被业务类实现继承.

(5) 使用不同的事务管理器

一般情况下,一个应用仅需要使用一个事务管理器.如果希望在不同的地方使用不同的事务管 理,@Transactional注解同样支持!

实现代码:

@Transactional("事务管理器的名字") //此处添加指定事务管理器的名字
@Service("accountService")
public class AccountServiceImpl implements AccountService {}

对应事务查找事务管理器的名字应该在xml中进行定义,如下:

<!--声明一个事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
    <qualifier value="定义事务管理器的名字,可以被注解查找" />
</bean>