Spring框架学习

Spring声明式事务为何不回滚---探究

2018-09-14  本文已影响28人  ___TheOne___

1.spring事务不回滚的两个原因

总结一下导致事务不回滚的两个原因:一是Service类内部方法调用,二是try...catch异常。
详细内容请见Spring声明式事务为何不回滚

2.Spring声明式事务配置 + SpringDataJPA 测试

使用代码测试 + 结合控制台debug日志,探究AOP在service方法添加事务细节。

声明式事务xml配置,spring-data-jpa.xml

<!-- Jpa事务管理器 start-->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>
    <!-- Jpa事务管理器 end-->

    <tx:advice id="transactionAdvice" transaction-manager="transactionManager">
        <!-- 配置详细事务处理语义 -->
        <tx:attributes>
            <tx:method name="add*" propagation="REQUIRED"/>
            <tx:method name="save*" propagation="REQUIRED"/>
            <tx:method name="insert*" propagation="REQUIRED"/>
            <tx:method name="del*" propagation="REQUIRED"/>
            <tx:method name="update*" propagation="REQUIRED"/>
            <tx:method name="new*" propagation="REQUIRED"/>

            <tx:method name="get*" read-only="true" propagation="REQUIRED"/>
            <tx:method name="query*" read-only="true" propagation="REQUIRED"/>
            <tx:method name="find*" read-only="true" propagation="REQUIRED"/>

            <tx:method name="*" propagation="SUPPORTS" rollback-for="Exception" read-only="true"/>
        </tx:attributes>
    </tx:advice>

    <aop:config>  <!--expose-proxy="true" proxy-target-class="true"-->
        <aop:pointcut id="transactionPointcut"
                      expression="execution(* org.jaden..service..*.*(..))"/>
        <aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice"/>
    </aop:config>

Part1:(正确做法)Service类内部方法调用,但是保证外围方法加上事务
答:外围方法通过xml声明式事务配置加上事务,即第一条标注(------)的日志展示的;当执行到内部方法时,Spring发现当前线程已有事务,因为事务级别是required,就加入当前事务执行。即:日志展示的"JpaTransactionManager:476 - Participating in existing transaction"。这样便能保证事务完整性,能够正常回滚。

15:07:38,676 DEBUG http-nio-8080-exec-5 servlet.DispatcherServlet:869 - DispatcherServlet with name 'dispatcher' processing GET request for [/trans/noRollback]
15:07:38,677 DEBUG http-nio-8080-exec-5 annotation.RequestMappingHandlerMapping:310 - Looking up handler method for path /trans/noRollback
15:07:38,677 DEBUG http-nio-8080-exec-5 annotation.RequestMappingHandlerMapping:317 - Returning handler method [public void org.jaden.jpa.controller.TransNoRollbackController.booksList(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)]
15:07:38,677 DEBUG http-nio-8080-exec-5 support.DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'transNoRollbackController'
15:07:38,677 DEBUG http-nio-8080-exec-5 servlet.DispatcherServlet:955 - Last-Modified value for [/trans/noRollback] is: -1

------15:07:38,678 DEBUG http-nio-8080-exec-5 jpa.JpaTransactionManager:367 - Creating new transaction with name [org.jaden.jpa.service.transactionNoRollback.TransNoRollbackService.updateSynBooks]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT------

15:07:38,678 DEBUG http-nio-8080-exec-5 jpa.JpaTransactionManager:371 - Opened new EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@1a308fab] for JPA transaction
15:07:38,679 DEBUG http-nio-8080-exec-5 spi.AbstractTransactionImpl:160 - begin
15:07:38,679 DEBUG http-nio-8080-exec-5 internal.LogicalConnectionImpl:226 - Obtaining JDBC connection
15:07:38,679 DEBUG http-nio-8080-exec-5 internal.LogicalConnectionImpl:232 - Obtained JDBC connection
15:07:38,680 DEBUG http-nio-8080-exec-5 jdbc.JdbcTransaction:69 - initial autocommit status: true
15:07:38,680 DEBUG http-nio-8080-exec-5 jdbc.JdbcTransaction:71 - disabling autocommit
15:07:38,681 DEBUG http-nio-8080-exec-5 jpa.JpaTransactionManager:403 - Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@7d4aa0b]
------15:07:38,681 DEBUG http-nio-8080-exec-5 jpa.JpaTransactionManager:334 - Found thread-bound EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@1a308fab] for JPA transaction------


------15:07:38,681 DEBUG http-nio-8080-exec-5 jpa.JpaTransactionManager:476 - Participating in existing transaction------

15:07:38,682 DEBUG http-nio-8080-exec-5 spi.ActionQueue:194 - Executing identity-insert immediately
15:07:38,683 DEBUG http-nio-8080-exec-5 hibernate.SQL:109 - 
    insert 
    into
        books
        (author, create_time, description, name, price, update_time) 
    values
        (?, ?, ?, ?, ?, ?)

Part2:Service类内部方法调用---导致的事务未回滚(前提是外围方法不加事务)
答:第三条标注的日志行信息,JpaTransactionManager:869 - Should roll back transaction but cannot - no transaction available


*********************************Condition2:方法A没有事务,方法B有事务:无法按照预期回滚,有可能导致数据库数据不一致。*********************************


------16:02:47,977 DEBUG http-nio-8080-exec-3 support.TransactionalRepositoryProxyPostProcessor$CustomAnnotationTransactionAttributeSource:351 - Adding transactional method 'save' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''------

16:02:47,988 DEBUG http-nio-8080-exec-3 support.DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'transactionManager'
------16:02:47,993 DEBUG http-nio-8080-exec-3 jpa.JpaTransactionManager:367 - Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''------
16:02:47,998 DEBUG http-nio-8080-exec-3 jpa.JpaTransactionManager:371 - Opened new EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@2101e4dc] for JPA transaction
16:02:48,013 DEBUG http-nio-8080-exec-3 spi.AbstractTransactionImpl:160 - begin
16:02:48,019 DEBUG http-nio-8080-exec-3 internal.LogicalConnectionImpl:226 - Obtaining JDBC connection
16:02:48,028 DEBUG http-nio-8080-exec-3 internal.LogicalConnectionImpl:232 - Obtained JDBC connection
16:02:48,034 DEBUG http-nio-8080-exec-3 jdbc.JdbcTransaction:69 - initial autocommit status: true
16:02:48,040 DEBUG http-nio-8080-exec-3 jdbc.JdbcTransaction:71 - disabling autocommit
16:02:48,053 DEBUG http-nio-8080-exec-3 jpa.JpaTransactionManager:403 - Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@b858432]
16:02:48,174 DEBUG http-nio-8080-exec-3 spi.ActionQueue:194 - Executing identity-insert immediately
16:02:48,218 DEBUG http-nio-8080-exec-3 hibernate.SQL:109 - 
    insert 
    into
        books
        (author, create_time, description, name, price, update_time) 
    values
        (?, ?, ?, ?, ?, ?)
Hibernate: 
    insert 
    into
        books
        (author, create_time, description, name, price, update_time) 
    values
        (?, ?, ?, ?, ?, ?)
16:02:48,325 DEBUG http-nio-8080-exec-3 id.IdentifierGeneratorHelper:94 - Natively generated identity: 32
16:02:48,336 DEBUG http-nio-8080-exec-3 pool.PreparedStatementPool:121 - {conn-10005, pstmt-20000} enter cache
16:02:48,362 DEBUG http-nio-8080-exec-3 jpa.JpaTransactionManager:759 - Initiating transaction commit
16:02:48,366 DEBUG http-nio-8080-exec-3 jpa.JpaTransactionManager:512 - Committing JPA transaction on EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@2101e4dc]
16:02:48,370 DEBUG http-nio-8080-exec-3 spi.AbstractTransactionImpl:175 - committing
16:02:48,377 DEBUG http-nio-8080-exec-3 internal.AbstractFlushingEventListener:149 - Processing flush-time cascades
16:02:48,385 DEBUG http-nio-8080-exec-3 internal.AbstractFlushingEventListener:189 - Dirty checking collections
16:02:48,401 DEBUG http-nio-8080-exec-3 internal.AbstractFlushingEventListener:123 - Flushed: 0 insertions, 0 updates, 0 deletions to 1 objects
16:02:48,407 DEBUG http-nio-8080-exec-3 internal.AbstractFlushingEventListener:130 - Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
16:02:48,423 DEBUG http-nio-8080-exec-3 util.EntityPrinter:114 - Listing entities:
16:02:48,428 DEBUG http-nio-8080-exec-3 util.EntityPrinter:121 - org.jaden.jpa.entity.Books{createTime=Wed Sep 12 16:02:38 CST 2018, author=null, price=null, name=Spring事务未回滚研究111, description=好好学习,天天向上, updateTime=null, id=32}
16:02:48,435 DEBUG http-nio-8080-exec-3 jdbc.JdbcTransaction:113 - committed JDBC Connection
16:02:48,439 DEBUG http-nio-8080-exec-3 jdbc.JdbcTransaction:126 - re-enabling autocommit
16:02:48,447 DEBUG http-nio-8080-exec-3 jpa.JpaTransactionManager:600 - Closing JPA EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@2101e4dc] after transaction
16:02:48,451 DEBUG http-nio-8080-exec-3 jpa.EntityManagerFactoryUtils:435 - Closing JPA EntityManager
16:02:48,456 DEBUG http-nio-8080-exec-3 internal.LogicalConnectionImpl:246 - Releasing JDBC connection
16:02:48,461 DEBUG http-nio-8080-exec-3 internal.LogicalConnectionImpl:264 - Released JDBC connection
16:02:48,468 DEBUG http-nio-8080-exec-3 jpa.JpaTransactionManager:1021 - Resuming suspended transaction after completion of inner transaction

------16:03:00,788 DEBUG http-nio-8080-exec-3 jpa.JpaTransactionManager:869 - Should roll back transaction but cannot - no transaction available------

16:03:00,798 DEBUG http-nio-8080-exec-3 annotation.ExceptionHandlerExceptionResolver:133 - Resolving exception from handler [public void org.jaden.jpa.controller.TransNoRollbackController.booksList(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)]: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer

Part3:try-catch异常---导致的事务未回滚
答:在默认配置中,Spring FrameWork 的事务框架代码只会将出现runtime, unchecked 异常的事务标记为回滚;也就是说事务中抛出的异常时RuntimeException或者是其子类,这样事务才会回滚(默认情况下Error也会导致事务回滚)。在默认配置的情况下,所有的 checked 异常都不会引起事务回滚。

将rollback-for,更改为MyCheckedException。让checkedException也可以回滚

------18:39:18,869 DEBUG http-nio-8080-exec-4 jpa.JpaTransactionManager:367 - Creating new transaction with name [org.jaden.jpa.service.transactionNoRollback.TransNoRollbackService.addBookHaveException]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-MyCheckedException------
18:39:18,874 DEBUG http-nio-8080-exec-4 jpa.JpaTransactionManager:371 - Opened new EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@2bc93598] for JPA transaction
18:39:18,889 DEBUG http-nio-8080-exec-4 spi.AbstractTransactionImpl:160 - begin
18:39:18,893 DEBUG http-nio-8080-exec-4 internal.LogicalConnectionImpl:226 - Obtaining JDBC connection
18:39:18,897 DEBUG http-nio-8080-exec-4 internal.LogicalConnectionImpl:232 - Obtained JDBC connection
18:39:18,902 DEBUG http-nio-8080-exec-4 jdbc.JdbcTransaction:69 - initial autocommit status: true
18:39:18,906 DEBUG http-nio-8080-exec-4 jdbc.JdbcTransaction:71 - disabling autocommit
18:39:18,917 DEBUG http-nio-8080-exec-4 jpa.JpaTransactionManager:403 - Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@202aace7]
18:39:19,458 DEBUG http-nio-8080-exec-4 support.TransactionalRepositoryProxyPostProcessor$CustomAnnotationTransactionAttributeSource:351 - Adding transactional method 'save' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
18:39:19,469 DEBUG http-nio-8080-exec-4 support.DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'transactionManager'
18:39:19,474 DEBUG http-nio-8080-exec-4 jpa.JpaTransactionManager:334 - Found thread-bound EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@2bc93598] for JPA transaction
18:39:19,479 DEBUG http-nio-8080-exec-4 jpa.JpaTransactionManager:476 - Participating in existing transaction
18:39:19,588 DEBUG http-nio-8080-exec-4 spi.ActionQueue:194 - Executing identity-insert immediately
18:39:19,634 DEBUG http-nio-8080-exec-4 hibernate.SQL:109 - 
    insert 
    into
        books
        (author, create_time, description, name, price, update_time) 
    values
        (?, ?, ?, ?, ?, ?)
Hibernate: 
    insert 
    into
        books
        (author, create_time, description, name, price, update_time) 
    values
        (?, ?, ?, ?, ?, ?)
18:39:19,739 DEBUG http-nio-8080-exec-4 id.IdentifierGeneratorHelper:94 - Natively generated identity: 37
18:39:19,750 DEBUG http-nio-8080-exec-4 pool.PreparedStatementPool:121 - {conn-10005, pstmt-20000} enter cache
18:39:34,565 DEBUG http-nio-8080-exec-4 jpa.JpaTransactionManager:851 - Initiating transaction rollback
------18:39:34,565 DEBUG http-nio-8080-exec-4 jpa.JpaTransactionManager:538 - Rolling back JPA transaction on EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@2bc93598]------
------18:39:34,565 DEBUG http-nio-8080-exec-4 spi.AbstractTransactionImpl:205 - rolling back------
18:39:34,572 DEBUG http-nio-8080-exec-4 jdbc.JdbcTransaction:164 - rolled JDBC Connection
18:39:34,572 DEBUG http-nio-8080-exec-4 jdbc.JdbcTransaction:126 - re-enabling autocommit
18:39:34,575 DEBUG http-nio-8080-exec-4 jpa.JpaTransactionManager:600 - Closing JPA EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@2bc93598] after transaction
18:39:34,575 DEBUG http-nio-8080-exec-4 jpa.EntityManagerFactoryUtils:435 - Closing JPA EntityManager
18:39:34,576 DEBUG http-nio-8080-exec-4 internal.LogicalConnectionImpl:246 - Releasing JDBC connection
18:39:34,576 DEBUG http-nio-8080-exec-4 internal.LogicalConnectionImpl:264 - Released JDBC connection
org.jaden.jpa.service.transactionNoRollback.MyCheckedException

3.精华文章参考

1.Spring声明式事务为何不回滚
2.关于 Spring 事务注解的几个不能忽视的细节

上一篇下一篇

猜你喜欢

热点阅读