admin管理员组

文章数量:1558103

@Transactional 同一个类中无事务方法a()内部调用有事务方法b()的问题

Methods should not call same-class methods with incompatible "@Transactional" values

When using Spring proxies, calling a method in the same class (e.g. this.aMethod()) with an incompatible @Transactional requirement will result in runtime exceptions because Spring only "sees" the caller and makes no provisions for properly invoking the callee.

Therefore, certain calls should never be made within the same class:

From To
non-@Transactional MANDATORY, NESTED, REQUIRED, REQUIRES_NEW
MANDATORY NESTED, NEVER, NOT_SUPPORTED, REQUIRES_NEW
NESTED NESTED, NEVER, NOT_SUPPORTED, REQUIRES_NEW
NEVER MANDATORY, NESTED, REQUIRED, REQUIRES_NEW
NOT_SUPPORTED MANDATORY, NESTED, REQUIRED, REQUIRES_NEW
REQUIRED or @Transactional NESTED, NEVER, NOT_SUPPORTED, REQUIRES_NEW
REQUIRES_NEW NESTED, NEVER, NOT_SUPPORTED, REQUIRES_NEW
SUPPORTS MANDATORY, NESTED, NEVER, NOT_SUPPORTED, REQUIRED, REQUIRES_NEW

Noncompliant Code Example

@Override
public void doTheThing() {
  // ...
  actuallyDoTheThing();  // Noncompliant
}

@Override
@Transactional
public void actuallyDoTheThing() {
  // ...
}

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only↵ at org.springframework.transaction.support.AbstractPlatformTransactionManagermit(AbstractPlatformTransactionManager.java:724)↵ at org.springframework.transaction.interceptor.TransactionAspectSupportmitTransactionAfterReturning(TransactionAspectSupport.java:518)↵ at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:292)↵ at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)↵ at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)↵ at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:97)↵ at com.chanjet.paasmon.base.interceptor.ExceptionInterceptor.around(ExceptionInterceptor.java:63)↵ at sun.reflect.GeneratedMethodAccessor85.invoke(Unknown Source)↵ at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)↵ at java.lang.reflect.Method.invoke(Method.java:498)↵ at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:629)↵ at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:618)↵ at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)↵ at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168)↵ at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)↵ at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)↵ at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)↵

Spring事务分类

Spring 提供了两种事务管理方式:声明式事务管理和编程式事务管理。

 

图解SPRING事务

声明式事务

配置方式

注:以下配置代码参考自Spring事务配置的五种方式

根据代理机制的不同,总结了五种Spring事务的配置方式,配置文件如下:

1、每个Bean有一个代理

2、所有Bean共享一个代理基类
3、使用拦截器
4、使用tx标签配置拦截器
<!-- 事务管理 -->
<bean  >
   <property name="dataSource" ref="dataSource" />
</bean>
<!-- 使用annotation定义事务 -->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target- />

<aop:config>
   <aop:advisor pointcut="execution(* com.*.*.event.local.service.*.*(..))" advice-ref="txAdviceLocalEvent"/>
</aop:config>

<tx:advice >
   <tx:attributes>
      <tx:method name="update*"/>
      <tx:method name="add*"/>
      <tx:method name="del*"/>
      <tx:method name="*" read-only="true"/>
   </tx:attributes>
</tx:advice>
5、全注解方式

一个声明式事务的实例

注:该实例参考自Spring中的事务管理实例详解

首先是数据库表 
book(isbn, book_name, price) 
account(username, balance) 
book_stock(isbn, stock)

然后是XML配置

<beans xmlns="http://www.springframework/schema/beans"
xmlns:xsi="http://www.w3/2001/XMLSchema-instance"
xmlns:context="http://www.springframework/schema/context"
xmlns:aop="http://www.springframework/schema/aop"
xmlns:tx="http://www.springframework/schema/tx"
xsi:schemaLocation="http://www.springframework/schema/beans
http://www.springframework/schema/beans/spring-beans-3.0.xsd
http://www.springframework/schema/context
http://www.springframework/schema/context/spring-context-3.0.xsd
http://www.springframework/schema/aop http://www.springframework/schema/aop/spring-aop-2.5.xsd
http://www.springframework/schema/tx http://www.springframework/schema/tx/spring-tx-2.5.xsd">

    <import resource="applicationContext-db.xml" />

    <context:component-scan
        base-package="com.springinaction.transaction">
    </context:component-scan>

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

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

</beans>

使用的类 
BookShopDao

package com.springinaction.transaction;

public interface BookShopDao {
   
    // 根据书号获取书的单价
    public int findBookPriceByIsbn(String isbn);
    // 更新书的库存,使书号对应的库存-1
    public void updateBookStock(String isbn);
    // 更新用户的账户余额:account的balance-price
    public void updateUserAccount(String username,

本文标签: 事务管理Spring