@Transactional
spring 事务注解
1.简单开启事务管理
@EnableTransactionManagement // 启注解事务管理,等同于xml配置方式的
<tx:annotation-driven />
2.事务注解详解
默认遇到throw new RuntimeException("...");会回滚
需要捕获的throw new Exception("...");不会回滚
指定回滚
@Transactional(rollbackFor=Exception.class)
public void methodName() {
// 不会回滚
throw new Exception("...");
}
指定不回滚
@Transactional(noRollbackFor=Exception.class)
public ItimDaoImpl getItemDaoImpl() {
// 会回滚
throw new RuntimeException("注释");
}
添加事物
@Transactional(propagation=Propagation.REQUIRED)
如果有事务,那么加入事务,没有的话新建一个(不写的情况下)@Transactional(propagation=Propagation.NOT_SUPPORTED)
容器不为这个方法开启事务@Transactional(propagation=Propagation.REQUIRES_NEW)
不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务@Transactional(propagation=Propagation.MANDATORY)
必须在一个已有的事务中执行,否则抛出异常@Transactional(propagation=Propagation.NEVER)
必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)@Transactional(propagation=Propagation.SUPPORTS)
如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务.
@Transactional(propagation=Propagation.NESTED)
public void methodName(){
// 本类的修改方法 1
update();
// 调用其他类的修改方法
otherBean.update();
// 本类的修改方法 2
update();
}
other失败了不会影响 本类的修改提交成功,本类update的失败,other也失败
readOnly=true只读,不能更新,删除
@Transactional (propagation = Propagation.REQUIRED,readOnly=true)
设置超时时间
@Transactional (propagation = Propagation.REQUIRED,timeout=30)
设置数据库隔离级别
@Transactional (propagation = Propagation.REQUIRED,isolation=Isolation.DEFAULT)
3.指定事务管理器
spring Boot 使用事务非常简单,首先使用注解 @EnableTransactionManagement 开启事务支持后,然后在访问数据库的Service方法上添加注解 @Transactional 便可。
-
事务管理器
不管JPA还是JDBC等都实现自接口 PlatformTransactionManager 如果添加spring-boot-starter-jdbc
依赖,框架会默认注入 DataSourceTransactionManager 实例。如果添加spring-boot-starter-data-jpa
依赖,框架会默认注入 JpaTransactionManager 实例。
你可以在启动类中添加如下方法,Debug测试,就能知道自动注入的是 PlatformTransactionManager 接口的哪个实现类。
-
打印项目事务管理器
@EnableTransactionManagement
启注解事务管理,等同于xml配置方式的 <tx:annotation-driven />
@SpringBootApplication
public class ProfiledemoApplication {
@Bean
public Object testBean(PlatformTransactionManager platformTransactionManager){
System.out.println(">>" + platformTransactionManager.getClass().getName());
return new Object();
}
public static void main(String[] args) {
SpringApplication.run(ProfiledemoApplication.class, args);
}
}
这些SpringBoot为我们自动做了,这些对我们并不透明,如果你项目做的比较大,添加的持久化依赖比较多,我们还是会选择人为的指定使用哪个事务管理器。
代码如下:
-
指定事务管理器
其中 dataSource 框架会自动为我们注入
@EnableTransactionManagement
@SpringBootApplication
public class ProfiledemoApplication {
@Bean
public PlatformTransactionManager txManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean
public Object testBean(PlatformTransactionManager platformTransactionManager) {
System.out.println(">>" + platformTransactionManager.getClass().getName());
return new Object();
}
public static void main(String[] args) {
SpringApplication.run(ProfiledemoApplication.class, args);
}
}
在Spring容器中,我们手工注解@Bean 将被优先加载,框架不会重新实例化其他的 PlatformTransactionManager 实现类。
然后在Service中,被 @Transactional 注解的方法,将支持事务。如果注解在类上,则整个类的所有方法都默认支持事务。
对于同一个工程中存在多个事务管理器要怎么处理,请看下面的实例,具体说明请看代码中的注释。
-
使用指定的事务管理器
// 开启注解事务管理,等同于xml配置文件中的 <tx:annotation-driven />
@EnableTransactionManagement
@SpringBootApplication
public class ProfiledemoApplication implements TransactionManagementConfigurer {
@Resource(name="txManager2")
private PlatformTransactionManager txManager2;
// 创建事务管理器1
@Bean(name = "txManager1")
public PlatformTransactionManager txManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
// 创建事务管理器2
@Bean(name = "txManager2")
public PlatformTransactionManager txManager2(EntityManagerFactory factory) {
return new JpaTransactionManager(factory);
}
// 实现接口 TransactionManagementConfigurer 方法
// 其返回值代表在拥有多个事务管理器的情况下默认使用的事务管理器
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return txManager2;
}
public static void main(String[] args) {
SpringApplication.run(ProfiledemoApplication.class, args);
}
}
@Component
public class DevSendMessage implements SendMessage {
// 使用value具体指定使用哪个事务管理器
@Transactional(value="txManager1")
@Override
public void send() {
System.out.println(">>>>>>>>Dev Send()<<<<<<<<");
send2();
}
// 在存在多个事务管理器的情况下,如果使用value具体指定
// 则默认使用方法 annotationDrivenTransactionManager() 返回的事务管理器
@Transactional
public void send2() {
System.out.println(">>>>>>>>Dev Send2()<<<<<<<<");
}
}
源码讲解
Spring 注解 事物开发
一、声明式事务:
环境搭建: 1、导入相关依赖 数据源、数据库驱动、Spring-jdbc模块
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
2、配置数据源、JdbcTemplate(Spring提供的简化数据库操作的工具)操作数据
3、给方法上标注 @Transactional 表示当前方法是一个事务方法;
4、 @EnableTransactionManagement 开启基于注解的事务管理功能;
5、配置事务管理器来控制事务transactionManager();
代码:
@Configuration
@EnableTransactionManagement
@ComponentScan("com.demo.tx")
public class TxConfig {
@Bean
public DataSource dataSource(){
DriverManagerDataSource ds = new DriverManagerDataSource ();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://192.168.0.1/demo");
ds.setUsername("root");
ds.setPassword("123456");
return ds;
}
@Bean
public JdbcTemplate jdbcTemplate(){
return new JdbcTemplate(dataSource());
}
@Bean
public PlatformTransactionManager transactionManager(){
return new DataSourceTransactionManager(dataSource());
}
}
二、事物原理部分
- @EnableTransactionManagement
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
- EnableTransactionManagement有三个属性,分别是proxyTargetClass、AdviceMode、order;它import了TransactionManagementConfigurationSelector
- proxyTargetClass设置为true表示使用基于子类实现的代理(
CGLIB
),设置为false表示使用基于接口实现的代理,默认为false - AdviceMode表示是使用哪种transactional advice,有PROXY及ASPECTJ两种,默认是AdviceMode.PROXY
Spring AOP使用JDK动态代理或CGLIB为给定目标对象创建代理。(默认使用JDK动态代理)。
如果被代理的目标对象已经实现了接口,则使用JDK动态代理。如果目标对象未实现任何接口,则会创建CGLIB代理。
如果要强制使用CGLIB代理,final 方法无法被覆盖不建议使用。要强制使用CGLIB代理,请将元素<aop:config>的属性proxy-target-class值设置为true,如下所示:
<aop:config proxy-target-class="true">
</aop:config>
代理原理区别
java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换。
-
TransactionManagementConfigurationSelector
TransactionManagementConfigurationSelector继承了抽象类AdviceModeImportSelector,它覆盖了selectImports,该方法根据adviceMode返回要创建的类名;如果是PROXY模式,则返回AutoProxyRegistrar.class.getName(),ProxyTransactionManagementConfiguration.class.getName();如果是ASPECTJ模式,则返回TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME或者是TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME
public class TransactionManagementConfigurationSelector
extends AdviceModeImportSelector<EnableTransactionManagement> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {TransactionManagementConfigUtils.
TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
-
AutoProxyRegistrar
给容器中注册一个 InfrastructureAdvisorAutoProxyCreator 组件
AutoProxyRegistrar.registerBeanDefinitions() -->
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); -->
registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAutoProxyCreatorIfNecessary(registry, null);
}
BeanDefinition registerAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, Object source) {
return registerOrEscalateApcAsRequired(
InfrastructureAdvisorAutoProxyCreator.class, registry, source);
//注册了一个InfrastructureAdvisorAutoProxyCreator组件
}
InfrastructureAdvisorAutoProxyCreator:?原理和AOP部分的AnnotationAwareAspectJAutoProxyCreator一样,利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用;
-
ProxyTransactionManagementConfiguration
给容器中注册事务增强器transactionAdvisor,事务增强器要用事务注解的信息,AnnotationTransactionAttributeSource解析事务注解,事务拦截器TransactionInterceptor保存了事务属性信息,
事务管理器是一个 MethodInterceptor;
@Configuration
public class ProxyTransactionManagementConfiguration
extends AbstractTransactionManagementConfiguration {
事物增强器
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor
= new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource());
advisor.setAdvice(transactionInterceptor());
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
3.1.2)、事务拦截器:
MethodInterceptor在目标方法执行的时候;执行拦截器链;
事务拦截器:
1)、先获取事务相关的属性
2)、再获取PlatformTransactionManager,如果事先没有添加指定任何transactionmanger最终会从容器中按照类型获取一个PlatformTransactionManager;
3)、执行目标方法
如果异常,获取到事务管理器,利用事务管理回滚操作;
如果正常,利用事务管理器,提交事务
3.1.2.1 MethodInterceptor在目标方法执行的时候;
TransactionInterceptor.invoke() 方法
@Override
public Object invoke(final MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
@Override
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}
3.1.2.2 TransactionAspectSupport.invokeWithinTransaction()方法
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
throws Throwable {
// 1)、先获取事务相关的属性
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
// 2)、再获取PlatformTransactionManager,如果事先没有添加指定任何transactionmanger
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
//获取要执行的事物方法
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// 创建一个事物
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
//事物方法的执行
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 有异常回滚事物
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
//得到事物管理器,提交事物
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
final ThrowableHolder throwableHolder = new ThrowableHolder();
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
new TransactionCallback<Object>() {
@Override
public Object doInTransaction(TransactionStatus status) {
TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
try {
return invocation.proceedWithInvocation();
}
catch (Throwable ex) {
if (txAttr.rollbackOn(ex)) {
// A RuntimeException: will lead to a rollback.
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
else {
throw new ThrowableHolderException(ex);
}
}
else {
// A normal return value: will lead to a commit.
throwableHolder.throwable = ex;
return null;
}
}
finally {
cleanupTransactionInfo(txInfo);
}
}
});
// Check result state: It might indicate a Throwable to rethrow.
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
}
return result;
}
catch (ThrowableHolderException ex) {
throw ex.getCause();
}
catch (TransactionSystemException ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
ex2.initApplicationException(throwableHolder.throwable);
}
throw ex2;
}
catch (Throwable ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
}
throw ex2;
}
}
}
3.1.2.2.1)、获取PlatformTransactionManager
如果事先没有添加指定任何transactionmanger最终会从容器中按照类型获取一个PlatformTransactionManager
protected PlatformTransactionManager determineTransactionManager(TransactionAttribute txAttr) {
// Do not attempt to lookup tx manager if no tx attributes are set
if (txAttr == null || this.beanFactory == null) {
return getTransactionManager();
}
//判断是否@Transactional(transactionManager = "")指定了transactionManager
String qualifier = txAttr.getQualifier();
if (StringUtils.hasText(qualifier)) {
return determineQualifiedTransactionManager(qualifier);
}
else if (StringUtils.hasText(this.transactionManagerBeanName)) {
return determineQualifiedTransactionManager(this.transactionManagerBeanName);
}
else {
PlatformTransactionManager defaultTransactionManager = getTransactionManager();
if (defaultTransactionManager == null) {
defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
if (defaultTransactionManager == null) {
defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class);
//在IOC容器中获取PlatformTransactionManager
this.transactionManagerCache.putIfAbsent(
DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
}
}
return defaultTransactionManager;
}
}