Spring源码分析之事务处理
前言
Spring对事务的支持依赖于SpringAOP的实现。
简单使用
create table test_db.tb_user(
u_id int auto_increment primary key, -- 主键自增
u_name varchar(20) null, -- 用户名
u_age int null -- 年龄
)
在MYSQL数据库创建一个用户表
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer uid;
private String uname;
private Integer age;
}
定义一个实体类,对应数据库的用户表
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.transaction.annotation.Transactional;
public class UserService {
@Autowired
private JdbcTemplate jdbcTemplate;
@Transactional
public void saveUser(User user) {
String sql = "insert into tb_user(u_name, u_age) VALUES (?,?)";
jdbcTemplate.update(sql, user.getUname(), user.getAge());
}
public List<User> queryUserList() {
String sql = "select * from tb_user";
RowMapper<User> rowMapper = new RowMapper<>() {
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
int uid = rs.getInt("u_id");
String uname = rs.getString("u_name");
int age = rs.getInt("u_age");
return new User(uid, uname, age);
}
};
return jdbcTemplate.query(sql, rowMapper);
}
}
创建用户业务类,查询用户列表,新增用户记录。使用@Transactional注解表示该方法开启事务控制。
import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
public class BeanConfig {
@Bean("userService")
public UserService userService() {
return new UserService();
}
@Bean("platformTransactionManager")
public PlatformTransactionManager platformTransactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean("dataSource")
public DataSource dataSource() {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl("jdbc:mysql://ip:3306/test_db");
dataSource.setUsername("xxx");
dataSource.setPassword("xxx");
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
return dataSource;
}
@Bean("jdbcTemplate")
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
配置数据库数据源,事务管理器等Bean。@EnableTransactionManagement开启事务管理。
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class TestTransactional {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
UserService userService = (UserService) context.getBean("userService");
System.out.println(userService.queryUserList());
User user = new User();
user.setUname("小李");
user.setAge(30);
userService.saveUser(user);
System.out.println(userService.queryUserList());
}
}
保存用户,查询用户,都可以正常工作。
原理分析
关于如何解析@Configuration注解,可以查看Spring源码分析之@Configuration注解的处理。
我们在它的基础上可以知道,开启事务的核心在于@EnableTransactionManagement注解,它会导入TransactionManagementConfigurationSelector配置。
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()};
//使用AspectJ,用的不多,先不用管
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}
}
会导入两个配置类
- AutoProxyRegistrar:
AutoProxyRegistrar是一个ImportBeanDefinitionRegistrar,会注册InfrastructureAdvisorAutoProxyCreator类,
和开启AOP的AnnotationAwareAspectJAutoProxyCreator类似,都是BeanPostProcessor,在创建Bean的过程中根据条件判断是否创建代理对象。
如果同时开启了事务和AOP,就是说同时注册InfrastructureAdvisorAutoProxyCreator和AnnotationAwareAspectJAutoProxyCreator,会使用后一个(优先级更高)。 - ProxyTransactionManagementConfiguration:
这是一个配置类,开启对@Transactional注解的拦截
关于AspectJ,可以查看AspectJ 使用介绍。
核心在于ProxyTransactionManagementConfiguration
@Configuration(proxyBeanMethods = false)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
//声明事务管理的Advisor,在包含@Transactional的方法上应用事务管理
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource,
TransactionInterceptor transactionInterceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource);
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
//内部使用SpringTransactionAnnotationParser来解析@Transactional注解
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
//具体的拦截器,事务处理的核心
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor(
TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
配置了一个Advisor,看过Spring源码分析之AOP使用和分析可以知道,
Advisor(通知器)包含Advice(通知)和Pointcut(切入点),这里的Pointcut就是类或方法包含@Transactional,Advice就是事务管理。
继续分析TransactionInterceptor,它是一个MethodInterceptor,也是Advice,处理实际的事务控制
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
//获取业务对象的Class,这里就是UserService
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
//执行事务控制
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
进入父类TransactionAspectSupport的invokeWithinTransaction()方法
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
TransactionAttributeSource tas = getTransactionAttributeSource();
//如果获取到的值为null,说明该方法不包含@Transactional注解
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
//从容器中获取类型为TransactionManager的Bean对象,这里就是我们配置的DataSourceTransactionManager
final TransactionManager tm = determineTransactionManager(txAttr);
//转换为PlatformTransactionManager类型
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
//当前方法的全路径,类路径.method
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
//创建TransactionInfo,其中包含一个数据库连接,且关闭了事务的自动提交
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
//执行业务方法,这里就是UserService的saveUser()方法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
//处理事务回滚,会判断当前异常和@Transactional注解配置的rollback是否匹配
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
//事务提交
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
}
}
创建TransactionInfo对象的过程中会处理事务传播行为
- TransactionDefinition.PROPAGATION_REQUIRED,
@Transactional注解默认行为。如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。 - TransactionDefinition.PROPAGATION_REQUIRES_NEW,
创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,都会新开启自己的事务,且开启的事务相互独立,互不干扰。 - TransactionDefinition.PROPAGATION_NESTED,
如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则创建一个新的事务。 - TransactionDefinition.PROPAGATION_MANDATORY
如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。 - TransactionDefinition.PROPAGATION_SUPPORTS
如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。 - TransactionDefinition.PROPAGATION_NOT_SUPPORTED
以非事务方式运行,如果当前存在事务,则把当前事务挂起。 - TransactionDefinition.PROPAGATION_NEVER
以非事务方式运行,如果当前存在事务,则抛出异常。
TransactionSynchronizationManager内部通过ThreadLocal来保存之前的事务。
分析总结
通过拦截包含@Transactional的类和方法,通过TransactionManager(事务管理器)来处理数据库连接的提交和回滚。