美文网首页
学习Spring5必知必会(7)~Spring tx

学习Spring5必知必会(7)~Spring tx

作者: 一乐乐 | 来源:发表于2022-03-13 09:28 被阅读0次

    一、spring的事务管理

    1、引出事务的经典例子:银行转账发生异常

    ✿ 解决:把转出钱和转入钱的业务放到同一个事务空间。

    ■ 分析转账过程流程:

    ① 首先,获取 DataSource 对象;
    ② 其次,获取 DataSource 中的 Connection 对象;
    ③ 接着,设置取消事务的自动提交方式: connection.setAutoCommit(false);
    ④ 然后,把 connection 绑定到当前线程中;
    从当前线程中获取 Connection 对象
    ⑥ 如果正常执行,则提交事务:提交事务:connection.commit(); 如果出现异常,则回滚事务:回滚事务:connection.rollback();



    2、Spring 的事务管理主要包括 3 个:PlatformTransactionManager、TransactionDefinition、TransactionStatus

    • PlatformTransactionManager:根据 TransactionDefinition 提供的事务属性配置信息,创建事务

    • TransactionDefinition:封装事务的隔离级别和超时时间,是否为只读事务和事务的隔离级别和传播规则等事务属性.

    • TransactionStatus: 封装了事务的具体运行状态。如是否是新开启事务,是否已经提交事务,设置当前事务为rollback-only.


    ■ PlatformTransactionManager

    图片.png

    ✿ 记:常用的事务管理器:

    • JDBC/MyBatis:DataSourceTransactionManager
    • Hibernate: HibernateTransactionManager


    3、事务传播规则 TransactionDefinition

    (1)事务的传播规则(传播行为):

    在一个事务方法中,调用了其他事务的方法,此时事务该如何传递,按照什么规则传播.

    图片.png

    (2)传播规则适应的情况:

    ■ 情况一:需要尊重/遵从当前事务

    • REQUIRED:(常用)必须存在一个事务,如果当前存在一个事务,则加入到该事务中,否则,新建一个事务.

    • SUPPORTS:支持当前事务,如果当前存在事务,则使用该事务,否则,以非事务形式运行.

    • MANDATORY:必须要存在事务,如果当存在事务,就使用该事务,否则,非法的事务状态异常:(IllegalTranactionStatusException)

    ■ 情况二:不遵从当前事务的

    • REQUIRES_NEW:(常用)不管当前是否存在事务,都会新开启一个事务.必须是一个新的事务.
    • NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,把当前事务挂起(暂停).
    • NEVER:不支持事务,如果当前存在事务,抛出一个异常.

    ■ 情况三:寄生事务(外部事务/内部事务/嵌套事务)

    • NESTED:寄生事务,如果当前存在事务,则在内部事务内执行.如果当前不存在事务,则创建一个新的事务.

      寄生事务可以通过数据库savePoint(保存点)来实现,奇生事务可以回滚的,但是他的回滚不影响外部事务.但是外部事务的回滚会影响寄生事务.

      • 寄生事务并不是所有的事务管理器都支持,比如HibernateTransactionManager默认就不支持,需要手动去开启.
      • Jdbc和MyBatis的事务管理器:DataSourceTransactionManager:默认就是支持的.



    二、事务配置

    1、使用xml配置jdbc事务

        <!-- ===============好比是AOP,事务增强================================== -->
        <!-- 1、what:配置jdbc事务管理器 -->
        <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean>
        
        <!-- 2:when:配置事务管理器增强(环绕增强) --><!-- 关联what -->
        <tx:advice id="txAdvice" transaction-manager="txManager">
            <tx:attributes>
                <tx:method name="trans"/>
            </tx:attributes>
        </tx:advice>
        
        <!-- 3、where:配置切面 --><!-- 关联when -->
        <aop:config>
            <aop:pointcut id="txPc" expression="execution(* com.shan.service.*Service.*(..))" />
            <aop:advisor advice-ref="txAdvice" pointcut-ref="txPc"/>
        </aop:config>
    


    2、事务增强的属性配置 <<tx:method/>> 元素的属性:

    属性 必要? 默认 描述
    name 匹配方法的模式
    propagation 事务的传播规则 required
    isolation 事务的隔离级别 default DEFAULT:使用数据库自身设置的隔离级别,其他四种都是Spring通过java代码模拟出来的
    timeout 事务超时时间 -1 缺省 -1 表示使用底层数据库自身的超时时间
    read-only 是否是只读事务 false 若对于查询方法,设置只读,会提高性能,例如Hibernate
    rollback-for 遇到什么异常做回滚 java.lang.RuntimeException 当我们在业务方法中,抛出一个Runtime异常,则事务回滚。自定义异常,若是需要配置多个异常,使用,隔开
    no-rollback-for 遇到什么异常不做回滚


    3、使用注解配置jdbc事务

    • 注解:@Transactional

    • 注解属性:name、propagation、isolation、timeout、read-only、rollback-for、no-rollback-for

    • 注解第三方解析:

      <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
      </bean>
      <!-- tx注解解析器 -->
      <tx:annotation-driven transaction-manager="txManager"/>
      

    ■ 注解@Transactional使用:

    @Service@Transactional
    public class AccountServiceImpl implements IAccountService{
        
        @Autowired
        private IAccountDAO dao;
    
        @Override
        public void trans(Long outId, Long inId, int money) {
            dao.transOut(outId, money);
            int a = 1/0; //算术异常
            dao.transIn(inId, money);   
        }
        
        //若是有查询方法,可以再贴注解@Transactional添加注解属性
        @Transactional(readOnly = true)
        public void listXX() {
            
        }
    
    }
    



    4、Java Config 配置

    @Configuration 配置

    @import(配置子类)

    @Bean 配置创建bean对象

    @ComponentScan ioc注解解析器

    @EnableTransactionManagement 事务注解解析器

    图片.png

    ■ DataSourceConfig.java

    //当前项目的连接池的配置类
    @Configuration
    @PropertySource("classpath:db.properties")
    public class DataSourceConfig {
        @Value("${jdbc.driverClassName}")
        private String driverClassName;
        @Value("${jdbc.url}")
        private String url;
        @Value("${jdbc.username}")
        private String username;
        @Value("${jdbc.password}")
        private String password;
        @Value("${jdbc.initialSize}")
        private int initialSize;
        
        //配置连接池的Bean
        @Bean
        public DataSource dataSource() {
            DruidDataSource ds = new DruidDataSource();
            ds.setDriverClassName(driverClassName);
            ds.setUrl(url);
            ds.setUsername(username);
            ds.setPassword(password);
            ds.setInitialSize(initialSize);
            return ds;
        }
    }
    

    ■ AppConfig.java

    //当前项目的配置类,好比是pplicationContext.xml
    @Configuration //标识当前类为一个配置类
    @Import(DataSourceConfig.class) //包含其他的配置类
    @ComponentScan //ioc注解解析器【di注解解析器默认是导入的】
    @EnableTransactionManagement//事务注解解析器
    public class AppConfig {
        
        //创建事务管理的Bean
        @Bean
        public DataSourceTransactionManager txManager(DataSource ds) {
            return new DataSourceTransactionManager(ds);
        }
    }
    

    ■ App.java

    @SpringJUnitConfig(classes = AppConfig.class)
    public class App {
        
        @Autowired
        private IAccountService service;
        
        @Test
        void testTrans() throws Exception {
            service.trans(1L, 2L, 100);
        }
    }
    


    写在后面的话

           如果你觉得一乐的文章给您带来了一些收获,可以给个三连❤️ ,一乐会一如既往地更新有价值的博客。如果文章存在错误,也欢迎大家指出。还有,如果大家有什么好的学习技巧、学习感悟,也非常欢迎大家在评论区一起交流~

    最后感谢大家的支持,谢谢~

    相关文章

      网友评论

          本文标题:学习Spring5必知必会(7)~Spring tx

          本文链接:https://www.haomeiwen.com/subject/krhprrtx.html