栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring事务

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring事务

   现如今,对于一个Java程序猿来说,如果说不会用甚至不知道Spring,那肯定不是一个合格的Java程序猿。大家都知道,Spring最主要的俩大模块,分别是IoC和AOP。而今天主要讲的是Spring中的事务@Transactional注解。
Sping事务的传播机制
名称解释
TransactionDefinition.PROPAGATION_REQUIRED如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
TransactionDefinition.PROPAGATION_REQUIRES_NEW创建一个新的事务,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_SUPPORTS如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER以非事务方式运行,如果当前存在事务,则抛出异常。
TransactionDefinition.PROPAGATION_MANDATORY如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
TransactionDefinition.PROPAGATION_NESTED如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
Spring事务简单应用

基于Spring AOP来实现Spring事务,加了注解@EnableTransactionManagement开启事务后,在类或者public方法上加上@Transactional注解就可以了。

pom.xml

    
      org.springframework
      spring-context
      5.3.10
    
    
      org.springframework
      spring-jdbc
      5.3.10
    
    
      mysql
      mysql-connector-java
      5.1.47
    

AppConfig.java

@ComponentScan("com.nxj.dev")
@Configuration
@EnableTransactionManagement
public class AppConfig {
​
    @Bean
    public JdbcTemplate jdbcTemplate() {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
        return jdbcTemplate;
    }
​
    @Bean
    public PlatformTransactionManager transactionManager() {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource());
        // 默认是true(事务 部分失败时,全局回滚)
        // 如果是false(事务 部分失败时,不回滚,都提交)
//        transactionManager.setGlobalRollbackOnParticipationFailure(true);
        return transactionManager;
    }
​
    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://ip:3306/spring_transaction?characterEncoding=utf-8&useSSL=false");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }
}

OrderService.java

@Component
public class OrderService {
    @Autowired
    JdbcTemplate jdbcTemplate;
​
    @Autowired
    OrderService orderService;
    
    // 1和2和3都插入失败
    @Transactional
    public void test1() {
        // 1
        jdbcTemplate.execute("insert into order_info values ('008', 8.88)");
        // 2
        jdbcTemplate.execute("insert into order_info values ('009', 9.99)");
        // 报错:java.lang.ArithmeticException: / by zero
        // Spring事务默认会在遇到RuntimeException、Error以及它们的子类的异常时,会回滚事务
        // 而ArithmeticException是RuntimeException的子类
        int i = 1/0;
        // 3
        jdbcTemplate.execute("insert into order_info values ('010', 10.00)");
    }
    
    // 1和2和3都成功
    @Transactional
    public void test2() throws SQLException {
        // 1
        jdbcTemplate.execute("insert into order_info values ('008', 8.88)");
        // 2
        jdbcTemplate.execute("insert into order_info values ('009', 9.99)");
        // 3
        jdbcTemplate.execute("insert into order_info values ('010', 10.00)");
        // Spring事务默认会在遇到RuntimeException、Error以及它们的子类的异常时,会回滚事务
        throw new SQLException();
    }    
    
    // 1和2和3都失败
    @Transactional(rollbackFor = Exception.class)
    public void test3() throws SQLException {
        // 1
        jdbcTemplate.execute("insert into order_info values ('008', 8.88)");
        // 2
        jdbcTemplate.execute("insert into order_info values ('009', 9.99)");
        // 3
        jdbcTemplate.execute("insert into order_info values ('010', 10.00)");
        // Spring事务默认会在遇到RuntimeException、Error以及它们的子类的异常时,会回滚事务
        throw new SQLException();
    }
    
    // 1和2和3都失败
    @Transactional
    public void test4() throws RuntimeException {
        // 1
        jdbcTemplate.execute("insert into order_info values ('008', 8.88)");
        // 2
        jdbcTemplate.execute("insert into order_info values ('009', 9.99)");
        // 3
        jdbcTemplate.execute("insert into order_info values ('010', 10.00)");
        // Spring事务默认会在遇到RuntimeException、Error以及它们的子类的异常时,会回滚事务
//        throw new RuntimeException();
        throw new Error();
    }    
    
    
    // 1和2都插入成功,3 失败
    public void test5() {
        a();
    }
​
    // 1和2和3 都失败
    public void test6() {
        // 在同一个类中,非事务方法调用事务方法,事务失效,得采用(Service)AopContext.currentProxy().xx()来进行调用,事务才能生效。
        ((OrderService) AopContext.currentProxy()).a();
    }
​
    // 1和2和3 都失败
    public void test7() {
        // 在同一个类中,非事务方法调用事务方法,事务失效,也可以采用自己注入自己,事务能生效。
        orderService.a();
    }
​
    @Transactional
    public void a() {
        // 1
        jdbcTemplate.execute("insert into order_info values ('008', 8.88)");
        // 2
        jdbcTemplate.execute("insert into order_info values ('009', 9.99)");
        // 报错:java.lang.ArithmeticException: / by zero
        int i = 1/0;
        // 3
        jdbcTemplate.execute("insert into order_info values ('010', 10.00)");
    }
    
    
    // 1和2和3都失败
    @Transactional
    public void test8() {
        // 1
        jdbcTemplate.execute("insert into order_info values ('008', 8.88)");
        b();
    }
​
    // 加不加@Transactional注解,都无所谓,因为同一个类中方法之间直接调用,被调用的方法上@Transactional失效
    @Transactional
    public void b() {
        // 2
        jdbcTemplate.execute("insert into order_info values ('009', 9.99)");
        int i = 1/0;
        // 3
        jdbcTemplate.execute("insert into order_info values ('010', 10.00)");
    }
    
    
    // 1和2成功,3失败
    @Transactional
    public void test9() {
        // 1
        jdbcTemplate.execute("insert into order_info values ('008', 8.88)");
        try {
            b();
        } catch (Exception e) {
​
        }
    }
​
    // 1和2和3失败
    @Transactional
    public void test10() {
        // 1
        jdbcTemplate.execute("insert into order_info values ('008', 8.88)");
        try {
            b();
        } catch (Exception e) {
            //手动强制回滚事务,然后可以抛出自定义的异常给前端
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }    
    
    // 1和2和3失败
    @Transactional
    public void test11() {
        // 1
        jdbcTemplate.execute("insert into order_info values ('008', 8.88)");
        try {
            orderService.b();
        } catch (Exception e) {
        }
    }   
​
    // 1和2都成功,3失败
    @Transactional
    public void test12() {
        // 1
        jdbcTemplate.execute("insert into order_info values ('008', 8.88)");
        orderService.c();
    }
​
    @Transactional
    public void c() {
        try {
            // 2
            jdbcTemplate.execute("insert into order_info values ('009', 9.99)");
            int i = 1/0;
            // 3
            jdbcTemplate.execute("insert into order_info values ('010', 10.00)");
        } catch (Exception e) {
​
        }
    }    
}
@EnableTransactionManagement
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
    
    boolean proxyTargetClass() default false;
​
    AdviceMode mode() default AdviceMode.PROXY;
​
    int order() default Ordered.LOWEST_PRECEDENCE;
}

可以看到,这个注解也挺简单的,就是通过@Import注解,引入了另外一个bean,通过查看TransactionManagementConfigurationSelector的类继承关系,可以发现,这个类实现了ImportSelector注解,所以,会实现selectImports()方法,在该方法中,注入了两个重要的bean

  1. AutoProxyRegistrar

  2. ProxyTransactionManagementConfiguration

AutoProxyRegistrar

AutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,所以,在registerBeanDefinitions方法中,注入一个bean

InfrastructureAdvisorAutoProxyCreator 可以发现,这个类是一个后置处理器,继承了InstantiationAwareBeanPostProcessor

所以:这就是@EnableTransactionManagement的第一个作用,注入了一个后置处理器,这个后置处理器就是用来对事务注解进行增强的

ProxyTransactionManagementConfiguration

该类只有一个注解@Configuration,所以该类是一个配置类,在该类中,通过三个@Bean注解,向spring容器中注入了事务执行时要用到的组件

    @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;
    }

所以:该类是给spring容器中,注入了三个bean,分别是:事务拦截器、事务解析器、事务增强器

Advisor=Advice+Pointcut

其中

Advisor=>BeanFactoryTransactionAttributeSourceAdvisor

Advice=>TransactionInterceptor

Pointcut=>TransactionAttributeSource=>TransactionAttributeSourcePointcut

参考链接:spring事务源码-代理对象生成过程解析_小小少年_的博客-CSDN博客_spring 事务代理对象

参考链接:公司新来一个同事,把 @Transactional 事务注解运用得炉火纯青。。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1013262.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号