Spring @Transactional 原理解析

项目准备

创建 dao 层

@Repository
public class AccountDao {
          
   

	@Autowired
	private JdbcTemplate jdbcTemplate;

	public void save() {
          
   
		jdbcTemplate.execute("INSERT INTO `mp`.`user`(`id`, `name`, `age`, `email`, `manager_id`, `create_time`, `update_time`, `version`, `deleted`) VALUES (777777, doudou, 40, boss@baomidou.com, NULL, 20190111142020, NULL, 1, 0);");
	}
}

创建 service 层

@Service
public class AccountService {
          
   

	@Autowired
	private AccountDao accountDao;

	@Transactional
	public void save() {
          
   
		accountDao.save();
		String str = null;
		str.length();
	}
}

创建事物配置文件

@Configuration
@ComponentScan("com.user.service")
@EnableTransactionManagement        // 开启事物管理
public class TxConfig {
          
   

	/**
	 * 数据源
	 */
	@Bean
	public DataSource dataSource() {
          
   
		DriverManagerDataSource dataSource = new DriverManagerDataSource();
		dataSource.setUsername("root");
		dataSource.setPassword("123456");
		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
		//dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
		dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/mp");
		return dataSource;
	}

	/**
	 * jdbc template
	 */
	@Bean
	public JdbcTemplate jdbcTemplate(DataSource dataSource) {
          
   
		return new JdbcTemplate(dataSource);
	}

	/**
	 * 平台事物管理
	 */
	@Bean
	public PlatformTransactionManager transactionManager(DataSource dataSource) {
          
   
		return new DataSourceTransactionManager(dataSource);
	}
}

启动类

public class TxMain {
          
   
	public static void main(String[] args) {
          
   
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TxConfig.class);
		AccountService accountService = (AccountService) applicationContext.getBean("accountService");
		accountService.save();
		applicationContext.close();
	}
}

事物不生效场景

具体场景参考第一张图


源码解读

开启事物

    通过 @EnableTransactionManagement 注解开启事物,该注解会 @Import TransactionManagementConfigurationSelector,Selector 是一个 ImportSelector,selectImports() 方法 返回 AutoProxyRegistrar、ProxyTransactionManagementConfiguration,这样就相当于开启代理功能和事物管理功能 ProxyTransactionManagementConfiguration 是一个被 @Configuration 标注的配置类,会将下面三个对象注册到 bean 容器中 TransactionAttributeSource:事物的属性源,用来获取事物的相关配置 TransactionInterceptor:事物的拦截器,获取事物、执行业务、判断是否抛异常、提交或回滚事物 BeanFactoryTransactionAttributeSourceAdvisor:事物属性源通知者,用于给 aop 提供事物属性源和拦截器

@Transaction 执行原理

1.代码入口

2.spring 事物由 aop 实现,所以方法调用会走代理

3.调用父类 proceed() 方法

4.aop 代理对象调用,调用 TransactionInterceptor 的 invoke()

5.调用事物拦截器,调用 TransactionAspectSupport 的 invokeWithinTransaction 处理事物

6.事物处理核心逻辑 判断事务是否开启、创建事物、目标方法执行、事务回滚、事务提交


private 导致事物不生效

2.重点:private 事物不生效原因 通过位与计算,判断是否为 Public,对应的几类修饰符如下: PUBLIC: 1 PRIVATE: 2 PROTECTED: 4


异常不匹配原因

1.回滚入口

2.重点,事物是否生效判断

3.进入 rollbackOn() 方法,判断该异常是否能进行回滚,这个需要判断主方法抛出的 Exception() 异常,是否在 @Transactional 的配置中

4.getDepth() 看一下异常规则匹配逻辑

5.默认捕获异常

经验分享 程序员 微信小程序 职场和发展