1.环境搭建
在pom.xml里加入数据库连接驱动和spring-jdbc的依赖。
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
创建TxConfig配置类,配置数据源和JdbcTemplate。
package com.atguigu.tx;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
@Configuration
@ComponentScan({"com.atguigu.tx"})
public class TxConfig {
@Bean
public DataSource dataSource() throws PropertyVetoException {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setUser("root");
comboPooledDataSource.setPassword("root");
comboPooledDataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&userSSL=false&serverTimezone=GMT%2B8");
return comboPooledDataSource;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
创建UserService和UserDao。
package com.atguigu.tx;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
UserDao userDao;
public void insert() {
userDao.insert();
}
}
package com.atguigu.tx;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class UserDao {
@Autowired
JdbcTemplate jdbcTemplate;
public void insert() {
String sql = "INSERT INTO user(name, age) VALUES(?, ?)";
jdbcTemplate.update(sql, "wangshaoyang", 24);
}
}
测试方法,此时是没有做事务处理的。
@Test
public void test() {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(TxConfig.class);
UserService userService = annotationConfigApplicationContext.getBean(UserService.class);
userService.insert();
}
2.测试事务
要想实现事务,需要分3个步骤。
- 需要在配置类上添加@EnableTransactionManagement
- 指定事务管理器,也就是需要在容器中添加一个PlatformTransactionManager对象,否则在运行时候,会提示数据源事务管理器找不到
- 在业务方法上添加@Transactional注解
@Bean
public PlatformTransactionManager platformTransactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
3.源码分析
查看@EnableTransactionManagement注解,它会Import一个TransactionManagementConfigurationSelector。查看TransactionManagementConfigurationSelector的selectImports()方法,它会根据adviceMode导入不同的组件。在EnableTransactionManagement类中可知,adviceMode默认值是PROXY,因此selectImports()导入是AutoProxyRegistrar组件和ProxyTransactionManagementConfiguration组件。
AutoProxyRegistrar组件:
给容器中导入InfrastructureAdvisorAutoProxyCreator组件,它也是一个后置处理器,后置处理器在对象创建后,包装对象,返回一个代理对象,代理对象执行拦截器链的方法。
ProxyTransactionManagementConfiguration组件:
给容器中注入BeanFactoryTransactionAttributeSourceAdvisor组件,AnnotationTransactionAttributeSource组件, TransactionInterceptor组件。其中AnnotationTransactionAttributeSource组件的构造器方法中会添加事务解析器,默认会添加SpringTransactionAnnotationParser。其中TransactionInterceptor保存了事务属性信息,事务管理器。查看TransactionInterceptor的invoke()方法,它会调用invokeWithinTransaction()方法。
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final TransactionAspectSupport.InvocationCallback invocation) throws Throwable {
// 获取事务相关属性
final TransactionAttribute txAttr = this.getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
// 获取平台事务管理器
final PlatformTransactionManager tm = this.determineTransactionManager(txAttr);
// 获取事务方法
final String joinpointIdentification = this.methodIdentification(method, targetClass, txAttr);
if (txAttr != null && tm instanceof CallbackPreferringPlatformTransactionManager) {
try {
Object result = ((CallbackPreferringPlatformTransactionManager)tm).execute(txAttr, new TransactionCallback<Object>() {
public Object doInTransaction(TransactionStatus status) {
TransactionAspectSupport.TransactionInfo txInfo = TransactionAspectSupport.this.prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
TransactionAspectSupport.ThrowableHolder var4;
try {
Object var3 = invocation.proceedWithInvocation();
return var3;
} catch (Throwable var8) {
if (txAttr.rollbackOn(var8)) {
if (var8 instanceof RuntimeException) {
throw (RuntimeException)var8;
}
throw new TransactionAspectSupport.ThrowableHolderException(var8);
}
var4 = new TransactionAspectSupport.ThrowableHolder(var8);
} finally {
TransactionAspectSupport.this.cleanupTransactionInfo(txInfo);
}
return var4;
}
});
if (result instanceof TransactionAspectSupport.ThrowableHolder) {
throw ((TransactionAspectSupport.ThrowableHolder)result).getThrowable();
} else {
return result;
}
} catch (TransactionAspectSupport.ThrowableHolderException var14) {
throw var14.getCause();
}
} else {
TransactionAspectSupport.TransactionInfo txInfo = this.createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// 执行事务方法
retVal = invocation.proceedWithInvocation();
} catch (Throwable var15) {
// 出现异常,在这个方法里,有rollback回调
this.completeTransactionAfterThrowing(txInfo, var15);
throw var15;
} finally {
this.cleanupTransactionInfo(txInfo);
}
// 如果没有异常,就执行提交操作
this.commitTransactionAfterReturning(txInfo);
return retVal;
}
}