spring-boot声明式事物使用及源码分析

环境准备

1、准备配置环境pom.xml包导入

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

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

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

注:这里只导入本次使用的包,其他的基础包不包含

2、设置数据库连接DataSource(数据源)和数据库连接驱动Driver

@Bean
DataSource getDataSource() throws Exception {
	String driver = "com.mysql.jdbc.Driver";
	String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai";
	//username=root
	//password=123456
	ComboPooledDataSource dataSource = new ComboPooledDataSource();
	dataSource.setUser("root");
	dataSource.setPassword("123456");
	dataSource.setJdbcUrl(url);
	dataSource.setDriverClass(driver);
	return dataSource;
}

@Bean
JdbcTemplate initJdbcTemplate(DataSource dataSource) {
	JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
	return jdbcTemplate;

}

3、测试时使用jdbcTemplate进行

4、要想方法具备事务功能,首先给方法加上@Transactional,那加上这个注解就起作用了吗?否

5、需要告诉spring容器,我要开启事务功能,并且你把事务相关的依赖组件帮我加载好;所以在配置类上面需要加上@EnableTransactionManagement注解

      开启事务(开启基于注解的事务) <tx:annotation-driven transaction-manager="transactionManager"/>  这个注解开启相当于xml配置的功能

6、由于开启了事务,在spring容器加载的时候,事务肯定需要某个东西管理,所以这里需要定义一个事务管理器,然后持有数据源(这样就可以控制数据源里面的是事务功能)

//事务管理器(把数据库连接交给他管理)
@Bean
TransactionManager getTransactionMa(DataSource dataSource) {
	return new DataSourceTransactionManager(dataSource);
}

一切准备就绪后,开始测试

@Repository
public class OrderDao {

    @Autowired
    JdbcTemplate jdbcTemplate;

    public void saveOrder() {
        String sql = "insert into `order`(id,id_product,`name`) values(?,?,?)";
        jdbcTemplate.update(sql, UUID.randomUUID().toString().replace("-",""),"1","奥尼啊");
    }
}

@Service
public class UserService {

    @Autowired
    private OrderDao orderDao;

    //如果这个方法抛出异常了,事务是会进行回滚的
    @Transactional
    public void addUser(){
        orderDao.saveOrder();
    }
}

/**
 * 1、导入依赖jar包
 * <dependency>
 * <groupId>org.springframework.boot</groupId>
 * <artifactId>spring-boot-starter-jdbc</artifactId>
 * </dependency>
 * <dependency>
 * <!--数据库连接池-->
 * <groupId>c3p0</groupId>
 * <artifactId>c3p0</artifactId>
 * <version>0.9.1.2</version>
 * </dependency>
 * 2、设置数据源、数据库驱动
 * 3、配置数据源,使用JdbcTemplate(测试)
 * 4、给方法上加入@Transactional注解,表示为事务方法
 * 5、需要开启事务管理功能@EnableTransactionManagement
 * 6、配置事务管理器,来管理事务,因为事务管理器需要持有数据库连接,只有拿到数据库连接才能控制实现对连接的
 *  提交还是回滚
 */
@Configuration
@ComponentScan("com.tractional")
@EnableTransactionManagement//开启事务(开启基于注解的事务) <tx:annotation-driven transaction-manager="transactionManager"/>
public class TxConfig {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TxConfig.class);
        UserService userService = context.getBean(UserService.class);
        userService.addUser();
    }

    //事务管理器(把数据库连接交给他管理)
    @Bean
    TransactionManager getTransactionMa(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean
    DataSource getDataSource() throws Exception {
        String driver = "com.mysql.jdbc.Driver";
        String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai";
        //username=root
        //password=123456
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser("root");
        dataSource.setPassword("123456");
        dataSource.setJdbcUrl(url);
        dataSource.setDriverClass(driver);
        return dataSource;
    }

    @Bean
    JdbcTemplate initJdbcTemplate(DataSource dataSource) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        return jdbcTemplate;

    }
}

到此为止,针对声明式事务的使用就OK了;


问???事务是如何起作用的,分析一下spring源码底层如何实现的?


【下面是思路,不是对源码一句一句代码进行分析,那样没意义:学源码学的是思想和人家的实现步骤,并不说去研究人家代码怎么写】
/**
     * 声明式事务实现原理
     * 1、只有开启了声明式事务,事务才会起作用
     * @see EnableTransactionManagement //@EnableTransactionManagement
     *   在注解EnableTransactionManagement中导入了@Import(TransactionManagementConfigurationSelector.class)
     *   利用TransactionManagementConfigurationSelector给容器导入组件(实现了ImportSelector接口)
     *      默认是AdviceMode为AdviceMode.PROXY
     *      所以导入了2个组件AutoProxyRegistrar和ProxyTransactionManagementConfiguration
     *      如果AdviceMode为AdviceMode.ASPECTJ(切面)
     *      导入组件AspectJJtaTransactionManagementConfiguration和AspectJTransactionManagementConfiguration
     * 2、AutoProxyRegistrar 干了什么事情【给容器注册了一个InfrastructureAdvisorAutoProxyCreator组件】
     *     AutoProxyRegistrar implements ImportBeanDefinitionRegistrar
     *     通过 AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)给容器注册了一个InfrastructureAdvisorAutoProxyCreator组件
     *     InfrastructureAdvisorAutoProxyCreator 又是做什么的呢?
     *          InfrastructureAdvisorAutoProxyCreator implements SmartInstantiationAwareBeanPostProcessor,BeanPostProcessor 后置处理器
     *          org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
     *             实现了这个方法 public Object postProcessAfterInitialization--这个在bean的后置处理器,
     *             也就是bean-InfrastructureAdvisorAutoProxyCreator创建完成后做的事情
     *             public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
     *                if (bean != null) {
     *                     Object cacheKey = getCacheKey(bean.getClass(), beanName);
     *                            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
     *                                return wrapIfNecessary(bean, beanName, cacheKey);
     *                            }
     *                        }
     *                    return bean;
     *             }
     *     利用bean的后置处理器在对象创建后,包装一个对象,返回一个代理对象(可以理解为是加了其他功能的增强对象),代理对象
     *     执行方法利用拦截器链的模式进行拦截处理(跟AOP思想一模一样)
     * 3、ProxyTransactionManagementConfiguration 干了什么事情
     *     @Configuration(proxyBeanMethods = false) 它是一个配置类
     *     1)、给容器注册transactionAdvisor:BeanFactoryTransactionAttributeSourceAdvisor事务增强器
     *         1)、需要事务属性transactionAttributeSource
     *         2)、事务拦截器transactionInterceptor
     *     2)、transactionAttributeSource:AnnotationTransactionAttributeSource 注解属性(用于解析@Transactional注解)
     *     3)、transactionInterceptor 事务拦截器
     *        TransactionInterceptor implements MethodInterceptor(也就是他是一个方法拦截器)
     *            需要设置interceptor.setTransactionManager(this.txManager)
     *            txManager是通过ImportAware设置,importMetadata.getAnnotationAttributes(EnableTransactionManagement)
     *            通过TransactionAspectSupport.determineTransactionManager
     *            beanFactory.getBean(TransactionManager.class)去找,找到了就缓存起来,也就是事务管理器,只要我们定义好bean注册到spring容器,这里就
     *            拿得到咯
     *        1)、transactionAttributeSource 注解属性
     *        2)、TransactionManager 事务管理器
     *        TransactionInterceptor--》invoke(MethodInvocation invocation)
     *          --》invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed)
     *          org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction核心方法,利用事务进行工作
     *        3)、事务处理 PlatformTransactionManager implements TransactionManager
     *          获取一个事务:TransactionManager.getTransaction(txAttr)
     *          事务提交:TransactionInfo.getTransactionManager().commit(txInfo.getTransactionStatus())
     *          回滚事务:TransactionInfo.getTransactionManager().rollback(txInfo.getTransactionStatus())
     *        4)、执行目标方法
     *          1)、如果没有异常,利用事务管理器的commit方法,提交事务
     *          2)、如果有异常,利用事务管理器的rollback,回滚事务
     *
     * 【实现原理跟https://blog.csdn.net/qqzhengwei/article/details/112788609】AOP的原理是一样的
     *
     */

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值