Spring注解驱动-声明式事务(六)

1.环境搭建

在pom.xml里加入数据库连接驱动和spring-jdbc的依赖。

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.18</version>
</dependency>
<dependency>
    <groupId>c3p0</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.1.2</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>4.3.12.RELEASE</version>
</dependency>

创建TxConfig配置类,配置数据源和JdbcTemplate。

package com.atguigu.tx;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;

@Configuration
@ComponentScan({"com.atguigu.tx"})
public class TxConfig {
    @Bean
    public DataSource dataSource() throws PropertyVetoException {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        comboPooledDataSource.setUser("root");
        comboPooledDataSource.setPassword("root");
        comboPooledDataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
        comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&userSSL=false&serverTimezone=GMT%2B8");
        return comboPooledDataSource;
    }

    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

创建UserService和UserDao。

package com.atguigu.tx;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    @Autowired
    UserDao userDao;

    public void insert() {
        userDao.insert();
    }
}
package com.atguigu.tx;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class UserDao {
    @Autowired
    JdbcTemplate jdbcTemplate;

    public void insert() {
        String sql = "INSERT INTO user(name, age) VALUES(?, ?)";
        jdbcTemplate.update(sql, "wangshaoyang", 24);
    }
}

测试方法,此时是没有做事务处理的。

@Test
public void test() {
    AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(TxConfig.class);
    UserService userService = annotationConfigApplicationContext.getBean(UserService.class);
    userService.insert();
}

2.测试事务

要想实现事务,需要分3个步骤。

  1. 需要在配置类上添加@EnableTransactionManagement
  2. 指定事务管理器,也就是需要在容器中添加一个PlatformTransactionManager对象,否则在运行时候,会提示数据源事务管理器找不到
  3. 在业务方法上添加@Transactional注解
@Bean
public PlatformTransactionManager platformTransactionManager(DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
}

3.源码分析

查看@EnableTransactionManagement注解,它会Import一个TransactionManagementConfigurationSelector。查看TransactionManagementConfigurationSelector的selectImports()方法,它会根据adviceMode导入不同的组件。在EnableTransactionManagement类中可知,adviceMode默认值是PROXY,因此selectImports()导入是AutoProxyRegistrar组件和ProxyTransactionManagementConfiguration组件。

AutoProxyRegistrar组件:

给容器中导入InfrastructureAdvisorAutoProxyCreator组件,它也是一个后置处理器,后置处理器在对象创建后,包装对象,返回一个代理对象,代理对象执行拦截器链的方法。

ProxyTransactionManagementConfiguration组件:

给容器中注入BeanFactoryTransactionAttributeSourceAdvisor组件,AnnotationTransactionAttributeSource组件, TransactionInterceptor组件。其中AnnotationTransactionAttributeSource组件的构造器方法中会添加事务解析器,默认会添加SpringTransactionAnnotationParser。其中TransactionInterceptor保存了事务属性信息,事务管理器。查看TransactionInterceptor的invoke()方法,它会调用invokeWithinTransaction()方法。

protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final TransactionAspectSupport.InvocationCallback invocation) throws Throwable {
    // 获取事务相关属性
    final TransactionAttribute txAttr = this.getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
    // 获取平台事务管理器
    final PlatformTransactionManager tm = this.determineTransactionManager(txAttr);
    // 获取事务方法
    final String joinpointIdentification = this.methodIdentification(method, targetClass, txAttr);
    if (txAttr != null && tm instanceof CallbackPreferringPlatformTransactionManager) {
        try {
            Object result = ((CallbackPreferringPlatformTransactionManager)tm).execute(txAttr, new TransactionCallback<Object>() {
                public Object doInTransaction(TransactionStatus status) {
                    TransactionAspectSupport.TransactionInfo txInfo = TransactionAspectSupport.this.prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
                    TransactionAspectSupport.ThrowableHolder var4;
                    try {
                        Object var3 = invocation.proceedWithInvocation();
                        return var3;
                    } catch (Throwable var8) {
                        if (txAttr.rollbackOn(var8)) {
                            if (var8 instanceof RuntimeException) {
                                throw (RuntimeException)var8;
                            }
                            throw new TransactionAspectSupport.ThrowableHolderException(var8);
                        }
                        var4 = new TransactionAspectSupport.ThrowableHolder(var8);
                    } finally {
                        TransactionAspectSupport.this.cleanupTransactionInfo(txInfo);
                    }
                    return var4;
                }
            });
            if (result instanceof TransactionAspectSupport.ThrowableHolder) {
                throw ((TransactionAspectSupport.ThrowableHolder)result).getThrowable();
            } else {
                return result;
            }
        } catch (TransactionAspectSupport.ThrowableHolderException var14) {
            throw var14.getCause();
        }
    } else {
        TransactionAspectSupport.TransactionInfo txInfo = this.createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
        Object retVal = null;
        try {
            // 执行事务方法
            retVal = invocation.proceedWithInvocation();
        } catch (Throwable var15) {
            // 出现异常,在这个方法里,有rollback回调
            this.completeTransactionAfterThrowing(txInfo, var15);
            throw var15;
        } finally {
            this.cleanupTransactionInfo(txInfo);
        }
        // 如果没有异常,就执行提交操作
        this.commitTransactionAfterReturning(txInfo);
        return retVal;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值