• 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);");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    创建 service 层

    @Service
    public class AccountService {
    
    	@Autowired
    	private AccountDao accountDao;
    
    	@Transactional
    	public void save() {
    		accountDao.save();
    		String str = null;
    		str.length();
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    创建事物配置文件

    @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);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    启动类

    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();
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    事物不生效场景

    具体场景参考第一张图


    源码解读

    开启事物

    • 通过 @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 导致事物不生效

    1.getTransactionAttribute(),关注获取事务配置的方法 computeTransactionAttribute()

    2.重点:private 事物不生效原因

    通过位与计算,判断是否为 Public,对应的几类修饰符如下:
    PUBLIC: 1
    PRIVATE: 2
    PROTECTED: 4


    异常不匹配原因

    1.回滚入口

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

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

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

    5.默认捕获异常

  • 相关阅读:
    Apache commons-dbutils工具简介说明
    阿里规范说MySQL单表行数不要超过2000w,为啥?
    腾讯云5年服务器2核4G和4核8G配置租用价格表
    leecode959. 由斜杠划分区域
    python多线程
    76. 最小覆盖子串
    浅谈本地缓存的几种方案选型
    PHP: GetCattle算法(N年后有多少头牛)(附完整源码)
    flask-socketio实现websocket通信
    移动端页面适配
  • 原文地址:https://blog.csdn.net/qq_41956014/article/details/126291460