初步理解@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

 

posted @ 2019-08-04 11:50  qee  阅读(722)  评论(0编辑  收藏  举报