一、事务的传播行为propagation
事务的第一个方面是传播行为(propagation /,prɒpə'ɡeɪʃən/ behavior)。
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。
规定了事务方法和事务方法发生嵌套调用时事务如何进行传播
例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。
Spring定义了七种传播行为:
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
(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.
* 读写事务属性:读/写事务.
* 超时时间:依赖于底层的事务系统默认值
* 回滚设置:任何运行期异常引发回滚,任何检查型异常不会引发回滚.
- 默认值可能适应大部分情况,但是我们依然可以可以自己设定属性,具体属性表如下:
- 在何处标注@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>