• 初步理解@Transactional注解


      在SSM项目中,经常在业务层的类或者方法上看到@Transactional注解,只是知道这个注解的作用是进行事务管理,但是具体有哪些属性,在什么情况下进行回滚,确是不那么清楚。所以在网上看了一些视频和博客,初步理解了Spring的事务管理。这里记录的主要是一些概念,如果想要能快速学会使用和理解事务管理,建议去相关视频。我看的是https://www.imooc.com/learn/478

      一、要理解Spring的事务管理,首先要了解什么是事务,事务有哪些特性,不遵守这些特性会出现什么问题。只有了解这些,才会理解事务管理要做什么。

        1.事务:逻辑上的一组操作,这组操作要么全部成功,要么全部失败。

        2.事务的特性

         (1)原子性:事务是一个不可分割的工作单位,事务中的操作在提交后要么全部成功,要么全部失败。

         (2)一致性:事务提交前后的数据的完整性必须保持一致。

         (3)隔离性:多个事务之间不会产生相互干扰,事务间的数据要相互隔离。

         (4)持久性:事务一单被提交,它对数据库的改变将是永久的,即使数据库发生故障也不应对其产生影响。

        3.如果事务不遵守上述的特性,则会出现脏读、不可重复读和幻读的问题

        (1)脏读:一个事务读取一个另一个事务改写但是还未提交的数据。如果这些数据回滚,则第一个事务读取到的数据将是无效的。

        (2)不可重复读:在同一个事务中,多次读取同一个数据的结果有所不同。

        (3)幻读:在一个事务读取数据后,另一个事务插入一些记录。当再次查询时,第一个事务将会发现原来没有的记录。

      二、了解了这些基础概念之后,再去了解Spring为事务管理提供的接口。

        1.PlatformTransactionManager:平台事务管理器接口。Spring为不同的持久化框架提供了不同的实现,如为Spring JDBC或MyBatis提供了DataSourceTransactionManager,

          为Hibernate提供了HibernateTransactionManager。事务管理器中定义了一些具体的事务操作,如事务提交、事务回滚。

        2.TransactionDefinition:事务定义信息。如事务隔离级别、传播行为、超时和只读。

        (1)事务隔离级别

          a)READ_UNCOMMITTED:允许读取另一个事务修改了但是还未提交的数据,会出现脏读、不可重复读和幻读的情况

          b)READ_COMMITTED:允许在另一个事务提交后读取数据,可防止脏读,但是会出现不可重复读和幻读。

          c)REPEATABLE_READ:对相同的数据的读取是一致的,除非事务本身修改了数据。可防止脏读和不可重复读,会出现幻读。

          d)SERIALIZABLE:该隔离级别是完全遵守ACID隔离级别的,能够确保不会发生脏读、不可重复读和幻读。但是由于读取相同数据的事务是完全串行读取的,所以执行速度非常慢。

          e)DEAFULT:Spring默认使用该隔离级别。表示使用后端数据库的默认隔离级别,MySQL的默认隔级别是REPEATABLE_READ,ORACLE的默认隔离级别是READ_COMMITTED。

        (2)传播行为,用于解决业务层中多个方法调用的问题

          a)PROPAGATION_REQUIRED:支持当前事务。如果当前事务存在,将另一个事务添加到当前事务中;如果当前事务不存在,则创建一个新的事务,并将第一个包含进去。

          b)PROPAGATION_SUPPORTS:支持当前事务。如果当前事务不存在,则以非事务方式执行。

          c)PROPAGATION_MANADATORY:支持当前事务。如果当前事务不存在,抛出异常。

          d)PROPAGATION_REQUIRES_NEW:新建事务,挂起当前事务,新建事务完成后再执行当前事务。

          e)PROPAGATION_NOT_SUPPORTS:以非事务方式执行。如果存在当前事务,则挂起当前事务。另一个方法执行完成后再执行当前事务。

          f)PROPAGATION_NEVER:以非事务方式运行。如果存在当前事务,则抛出异常。

          g)PROPAGATION_NESTED:若当前事务存在,则将第二个事务嵌套到当前事务中。

        (3)超时:默认为-1。设置超时时间后事务还未完成,则回滚事务。

        (4)只读:指定事务为只读事务,默认false。如果设置为true,事务中存在新增、删除和修改数据库则会抛出异常并回滚。

        3.TransactionStatus:事务具体运行状态。

      三、配置事务管理

        1.编程式事务管理:通过在方法中编写事务管理程序来实现事务管理,这种方式对业务层代码有侵入,很少使用。

            transactionTemplate.execute(new TransactionCallbackWithoutResult() {
                @Override
                protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                    accountDao.outMoney(out, money);
                    int i = 1 / 0;
                    accountDao.inMoney(in, money);
                }
            });

        

        2.声明式事务管理:

        (1)使用代理实现事务管理,需要为每一个类添加一个代理类,当需要事务管理的类增多时,添加代理类很麻烦。所以这个很少使用。

        <!--注入代理-->
        <bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
            <!--注入目标对象-->
            <property name="target" ref="declarativeAccountService" />
            <!--注入事物管理器-->
            <property name="transactionManager" ref="transactionManager" />
    
            <property name="transactionAttributes">
                <props>
                    <prop key="transfer">PROPAGATION_REQUIRED,+java.lang.ArithmeticException</prop>
                </props>
            </property>
        </bean>
        @Resource(name="accountServiceProxy")
        private DeclarativeAccountService declarativeAccountService;

        

        (2)使用AspectJ实现事务管理,需要配置增强通知和切面。需要事务管理的包或类很清晰。

        <!--配置事务通知-->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="transfer" propagation="REQUIRED"/>
            </tx:attributes>
        </tx:advice>
    
        <aop:config>
            <!--配置切入点-->
            <aop:pointcut id="aspectJPoint" expression="execution(* imooc.spring.transaction.manage.service.AspectJAccountService+.*(..))" />
            <!--配置切面-->
            <aop:advisor advice-ref="txAdvice" pointcut-ref="aspectJPoint" />
        </aop:config>

        

        (3)基于注解的事务管理:需要的步骤有1.配置事务管理器,可以在xml中配置,同时也可以使用注解配置 2.在类或方法上标注@Transactional注解。

    <tx:annotation-driven transaction-manager="transactionManager" />

      四、使用@Transactional注解需要注意的几点

        1.在类和方法上都可以标注@Transactional注解,同时在类或方法上标有@Transactional注解时,方法上的事务管理属性胡会覆盖类上的属性。

        2.@Transactional注解只有标注在public方法上时才会生效,标注在其它方法上不会报错,但是不能生效。

        3.默认情况下,事务中如果抛出未检查异常(RuntimeException或其子类)和ERROR时,事务将回滚;除此之外的异常将不会回滚。

          在阿里的p3c代码规范中要求在标注事务管理时添加rollbackFor属性,即@Transactional(rollbackFor=Exception.class)。

    上述概念都是在看完博客和视频后的一些记录,如果有错误的地方欢迎指正。如果有兴趣的,可以查阅相关博客和视频链接如下:

    https://www.cnblogs.com/xd502djj/p/10940627.html

    https://www.imooc.com/learn/478

  • 相关阅读:
    c语言中输出char类型所占据的位数(因编译器而异)
    C语言中输出不同变量类型的长度(单位为字节,1字节等于8位)
    C语言中作用域
    python 中字符串 内置函数 find
    python 中字符串拆分可直接赋值给变量名(列表中的元素可以直接赋值给变量)
    telnet协议
    LeetCode 图解 | 37.解数独
    新年锦鲤!自费送128G的 iPhone 11 !
    计算机领域有哪些常见的比赛
    Git 使用教程:最详细、最傻瓜、最浅显、真正手把手教!(万字长文)
  • 原文地址:https://www.cnblogs.com/yaqee/p/11297734.html
Copyright © 2020-2023  润新知