Spring声明式事务

事务代码
测试代码

0.环境准备

0.1 安装mysql

版本:mysql-installer-community-5.6.41.0.msi
账号/密码:root/root
端口:3307

0.2 在数据库test下创建表test

Spring声明式事务_第1张图片
CREATE TABLE order_tbl(
orderid INT NOT NULL AUTO_INCREMENT,
ordertime datetime DEFAULT NULL,
ordermoney decimal(20,0) DEFAULT NULL,
orderstatus char(1) DEFAULT NULL,
PRIMARY KEY(orderid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

在创建表的时候,发生error 1064 (42000)错误,是因为order是关键字,所以改为order_tbl,在mysql中使用与关键字同名的名字时,可以使用反引号(` `):


Spring声明式事务_第2张图片

0.3 使用相应的第三方组件

        
            c3p0
            c3p0
            0.9.1.2
        
        
            mysql
            mysql-connector-java
            5.1.44
        
        
            org.springframework
            spring-jdbc
            5.0.6.RELEASE
        

0.4 使用c3p0在配置类中创建数据源

@Configuration
@ComponentScan("com.wangzhen.ch11")
public class Ch11MainConfig {
    //创建数据源
    @Bean
    public DataSource dataSource() throws PropertyVetoException {
        //这个c3p0封装了JDBC, dataSource接口的实现
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser("root");
        dataSource.setPassword("root");
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3307/test");
        return dataSource;
    }

    //jdbcTemplate能简化增删改查的操作
    @Bean
    public JdbcTemplate jdbcTemplate() throws PropertyVetoException{
        return new JdbcTemplate(dataSource());
    }
}

0.5 业务类

  • 具体的数据库插入语句
@Repository
public class OrderDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    //操作数据的方法
    public void insert(){
        String sql = "insert into order_tbl (ordertime, ordermoney, orderstatus) values(?,?,?)";
        jdbcTemplate.update(sql,new Date(),20,0);
    }
}
  • service向外提供服务
@Service
public class OrderService {
    @Autowired
    private OrderDao orderDao;
    public void addOrder(){
        orderDao.insert();
        System.out.println("操作完成.........");
    }
}

0.6 测试

public class Ch11Test {
    @Test
    public void test01() {
        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Ch11MainConfig.class);

        OrderService bean = app.getBean(OrderService.class);
        bean.addOrder();

        app.close();
    }
}

结果:


Spring声明式事务_第3张图片

1.事务处理

  • @EnableTransactionalManagement开启基于注解的事务管理功能
  • 将事务管理器的bean加载到容器中(DataSourceTransactionManager)
@Configuration
@ComponentScan("com.wangzhen.ch11")
@EnableTransactionManagement
public class Ch11MainConfig {
    //创建数据源
    @Bean
    public DataSource dataSource() throws PropertyVetoException {
        //这个c3p0封装了JDBC, dataSource接口的实现
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser("root");
        dataSource.setPassword("root");
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3307/test");
        return dataSource;
    }

    //jdbcTemplate能简化增删改查的操作
    @Bean
    public JdbcTemplate jdbcTemplate() throws PropertyVetoException{
        return new JdbcTemplate(dataSource());
    }
    //注册事务管理器
    @Bean
    public PlatformTransactionManager platformTransactionManager() throws PropertyVetoException{
        return new DataSourceTransactionManager(dataSource());
    }
}
  • 给OrderService添加事务
@Service
public class OrderService {
    @Autowired
    private OrderDao orderDao;
    @Transactional
    public void addOrder(){
        orderDao.insert();
        System.out.println("操作完成.........");

        int a = 1/0;
    }
}
  • 事务执行结果


    Spring声明式事务_第4张图片

    Spring声明式事务_第5张图片

2.事务管理源码分析

2.1 @EnableTransactionManagement

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

TransactionManagementConfigurationSelector给容器导入两个组件:

  • AutoProxyRegistrar
  • ProxyTransactionManagementConfiguration
    protected String[] selectImports(AdviceMode adviceMode) {
        switch (adviceMode) {
            case PROXY:
                return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
            case ASPECTJ:
                return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
            default:
                return null;
        }
    }
  • selectImports执行时机(调用栈)


    Spring声明式事务_第6张图片

2.2 AutoProxyRegistrar

 * @author Chris Beams
 * @since 3.1
 * @see EnableAspectJAutoProxy
 */
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
  • registerBeanDefinitions执行时机(调用栈)


    Spring声明式事务_第7张图片

在该方法中注册了一个新的组件:InfrastructureAdvisorAutoProxyCreator。是基本的动态代理创建器。其beanName为org.springframework.aop.config.internalAutoProxyCreator。
利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用。

    @Nullable
    public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
            @Nullable Object source) {

        return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
    }
  • 调用栈如下


    Spring声明式事务_第8张图片

2.2.1 InfrastructureAdvisorAutoProxyCreator

Spring声明式事务_第9张图片

2.3 ProxyTransactionManagementConfiguration

Spring声明式事务_第10张图片
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

    @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
        BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
        advisor.setTransactionAttributeSource(transactionAttributeSource());
        advisor.setAdvice(transactionInterceptor());
        if (this.enableTx != null) {
            advisor.setOrder(this.enableTx.getNumber("order"));
        }
        return advisor;
    }

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionAttributeSource transactionAttributeSource() {
        return new AnnotationTransactionAttributeSource();
    }

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionInterceptor transactionInterceptor() {
        TransactionInterceptor interceptor = new TransactionInterceptor();
        interceptor.setTransactionAttributeSource(transactionAttributeSource());
        if (this.txManager != null) {
            interceptor.setTransactionManager(this.txManager);
        }
        return interceptor;
    }

}

2.3.1 AnnotationTransactionAttributeSource

事务增强器要用事务注解的信息,AnnotationTransactionAttributeSource解析事务注解。

Spring声明式事务_第11张图片

2.3.2 事务拦截器TransactionInterceptor

Spring声明式事务_第12张图片

TransactionInterceptor保存了事务属性信息和事务管理器,是一个 MethodInterceptor。
在目标方法执行的时候:

  • 执行拦截器链;
  • 事务拦截器:
    1)先获取事务相关的属性
    2)再获取PlatformTransactionManager,如果事先没有添加指定任何transactionmanger最终会从容器中按照类型获取一个PlatformTransactionManager;
    3)执行目标方法
    如果异常,获取到事务管理器,利用事务管理回滚操作;
    如果正常,利用事务管理器,提交事务

事务处理的关键方法:

    @Nullable
    protected Object invokeWithinTransaction(Method method, @Nullable Class targetClass,
            final InvocationCallback invocation) throws Throwable {

        // If the transaction attribute is null, the method is non-transactional.
        TransactionAttributeSource tas = getTransactionAttributeSource();
        final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
        final PlatformTransactionManager tm = determineTransactionManager(txAttr);
        final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

        if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
            // Standard transaction demarcation with getTransaction and commit/rollback calls.
            TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
            Object retVal = null;
            try {
                // This is an around advice: Invoke the next interceptor in the chain.
                // This will normally result in a target object being invoked.
                retVal = invocation.proceedWithInvocation();
            }
            catch (Throwable ex) {
                // target invocation exception
                completeTransactionAfterThrowing(txInfo, ex);
                throw ex;
            }
            finally {
                cleanupTransactionInfo(txInfo);
            }
            commitTransactionAfterReturning(txInfo);
            return retVal;
        }

        else {

调用栈:


Spring声明式事务_第13张图片

3.Spring事务总结

Spring声明式事务_第14张图片

参考

  • 1)享学课堂James老师笔记
  • 2)享学课堂zhq同学

你可能感兴趣的:(Spring声明式事务)