Spring学习笔记-声明式事务

       今天我们来聊一聊spring的声明式事务,了解spring中事务处理即实现,接下来从代码准备、事务开启条件以及原理源码分析三个方面来展开说明。

代码准备

      这部分我主要以基础的mysql加jdbcTemplate数据操作实现。

1、maven项目搭建,导入我们需要的数据库依赖以及spring操作数据库的依赖。

<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.3.12.RELEASE</version>
    </dependency>


     <dependency>
        <groupId>c3p0</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.1.2</version>
    </dependency>


    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.29</version>
    </dependency>

2、添加配置类,配置数据源、Spring提供操作数据库的工具JdbcTemplate以及事务管理器。


@EnableTransactionManagement
@Configuration
@ComponentScan(value = {"com.wjs.service","com.wjs.dao","com.wjs.tx"})
public class TxMainConfig {

    @Bean
    public DataSource dataSource() throws Exception{
        
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        
        dataSource.setUser("root");
        
        dataSource.setPassword("123456");
        
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
    
        return dataSource;
        
    }
    
    @Bean
    public JdbcTemplate jdbcTemplate() throws Exception{
        
        return new JdbcTemplate(dataSource());
        
    }
    
    @Bean
    public PlatformTransactionManager platformTransactionManager()  throws Exception{
        
        return new DataSourceTransactionManager(dataSource());
    }
    
}

 

3、对应的事务方法Service类,以及数据库操作Dao类,最后我们的测试类。

@Service
public class BookService {

    @Autowired
    private BookDao bookDao;
       
    @Transactional
    public void insert() {      
        
        String name = "beiecanshijie";
        
        String author = "lisi";
        
        int price = 30;
        
        bookDao.insert(name, author, price);
        
        System.out.println("插入完成!");
        
        int j = 1/0;
    }

}


@Repository
public class BookDao {
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    public void insert(String name,String author,int price){
        
        String sql = "INSERT into `book` (name,author,price)  VALUES (?,?,?)";
        
        jdbcTemplate.update(sql, name,author,price);
    }
    

}


public class SpringTxTest {
    
    @Test
    public void test(){
        
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TxMainConfig.class);
        
        BookService bookService = applicationContext.getBean(BookService.class);
        
        bookService.insert();
    }

}

 

4、最后因为我们加入了事务,所以在Service层抛出除0异常后,数据库并不会插入一条数据,若注释掉 @Transactional注解则会插入一条数据,接下来说一说开启事务的条件。

事务开启条件

       从上面的代码中,我们发现了两个新的注解 @Transactional 和 @EnableTransactionManagement,还有在配置类中我们加入了PlatformTransactionManager组件到容器中,这些就是开启事务的前提条件。

1、@Transactional,在我们的业务方法上加上该注解,表示当前方法是一个事务方法;

2、@EnableTransactionManagement,在我们的配置类上加入该注解表示开启基于注解的spring事务管理功能;

3,、添加PlatformTransactionManager组件,将该组件加入到spring容器中,配置事务管理器来控制事务;

原理分析

       首先说一下@EnableTransactionManagement注解,他向容器中加入了TransactionManagementConfigurationSelector组件,因为EnableTransactionManagement里面AdviceMode默认的是proxy,所以它的目的就是向我们的容器中加入AutoProxyRegistrar,ProxyTransactionManagementConfiguration这两个组件。

Spring学习笔记-声明式事务

Spring学习笔记-声明式事务

Spring学习笔记-声明式事务

AutoProxyRegistrar组件

        进入代码,在重写的registerBeanDefinitions方法中,它会去执行registerAutoProxyCreatorIfNecessary这个方法,而这个方法就是向我们容器中注册一个InfrastructureAdvisorAutoProxyCreator组件,注册该组件的意义就是,利用后置处理器的机制,在我们bean对象创建后,对该bean进行一个包装,返回一个该bean的代理对象,这个代理对象中包括我们的一些增强器advisor,在代理对象执行方法的时候,会对这个增强器做一个转换,变为methodInerceptor,然后在目标方法执行时做一个拦截处理,这块跟之前我们了解的AnnotationAwareAspectJAutoProxyCreator组件的创建其实是一个道理,具体过程详情可参考之前的aop原理分析进行了解 https://blog.csdn.net/wjs2580219863/article/details/107191308

Spring学习笔记-声明式事务

Spring学习笔记-声明式事务

ProxyTransactionManagementConfiguration组件

        这个组件实际上是一个配置类,它向我们容器中注册了一些组件包括事务增强器、事务属性信息以及事务拦截器。

1、事务增强器,增强器加入了注解的属性信息AnnotationTransactionAttributeSource()以及事务拦截器。

Spring学习笔记-声明式事务

        注解属性详细信息 AnnotationTransactionAttributeSource中主要就是拿到 @Transactional 这个注解后面括号中加入的一些属性信息并解析。

Spring学习笔记-声明式事务

Spring学习笔记-声明式事务

2,事务拦截器,主要是返回一个TransactionInterceptor,这个对象加入了我们的事务属性信息以及事务管理器,点击这个对象我们了解到TransactionInterceptor是implements MethodInterceptor的,所以它是一个方法拦截器,也就是我们代理对象执行目标方法的时候会先去执行这个拦截器。

Spring学习笔记-声明式事务

进入TransactionInterceptor对象的invoke方法,执行invokeWithinTransaction(),

Spring学习笔记-声明式事务

1、首选会拿到我们的事务的一些属性信息,

Spring学习笔记-声明式事务

2、再获取我们的事务管理器信息,

Spring学习笔记-声明式事务

 进入获取事务管理器方法,首先它会去判断这个qualifier有没有值,也就是去判断我们的事务方法@Transactional注解有没有添加transactionManager属性,没有设置的话,就去拿默认的事务管理器,当然默认的为空,然后spring就会根据这个PlatformTransactionManager类型从bean容器中去获取这个事务管理器,这就是我们为什么一开始在配置类中注册PlatformTransactionManager组件的原因,也是为什么一配置就能用事务管理器的原因。

Spring学习笔记-声明式事务

3,继续往下走,invocation.proceedWithInvocation(),也就是我们之前了解过的chain拦截器链以及proceed方法执行部分,

Spring学习笔记-声明式事务

如果事务方法抛出异常,则会在这个地方被捕获,然后执行completeTransactionAfterThrowing(txInfo, ex)方法,它实际上就是执行了事务管理器的回滚操作,txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());拿到事务管理器,执行回滚方法;

Spring学习笔记-声明式事务

如果事务方法正常执行,则执行commitTransactionAfterReturning(txInfo)方法,进行事务的commit操作,拿到事务管理器执行commit;

Spring学习笔记-声明式事务

        综合以上信息,我们就对spring事务的配置以及实现的原理有了个大概的了解。