zoukankan      html  css  js  c++  java
  • Spring事务管理

    Spring 事务管理

    Spring 为事务管理提供了丰富的功能支持。Spring 事务管理分为编程式和声明式的两种方式。编程式事务指的是通过编码方式实现事务(基本上不使用);声明式事务基于 AOP,将具体业务逻辑与事务处理解耦。声明式事务管理使业务代码逻辑不受污染, 因此在实际使用中声明式事务用的比较多。声明式事务有两种方式,一种是在配置文件(xml)中做相关的事务规则声明,另一种是基于@Transactional 注解的方式。

    xml配置声明事务

    XML配置文件:

    <!-- Spring中,使用XML配置事务的三大步骤:
    	1.创建事务管理器
    	2.配置事务方法
    	3.配置AOP
    	-->
    	
    	<!-- 1.事务管理器 -->
    	<bean id="transactionManager"
    		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    		<!-- 数据源 -->
    		<property name="dataSource" ref="dataSource" />
    	</bean>
    	
        <!-- 2.配置事务方法 -->       
        <!-- 通知 -->
    	<tx:advice id="txAdvice"
    		transaction-manager="transactionManager">
    		<tx:attributes>
               	<!-- 在需要开启事务的方法中,只要符合以下命名规则,就会执行事务 -->
                <!-- propagation设置事务的传播行为 -->
    			<tx:method name="save*" propagation="REQUIRED" />
    			<tx:method name="insert*" propagation="REQUIRED" />
    			<tx:method name="add*" propagation="REQUIRED" />
    			<tx:method name="create*" propagation="REQUIRED" />
    			<tx:method name="delete*" propagation="REQUIRED" />
    			<tx:method name="update*" propagation="REQUIRED" />
    			<tx:method name="find*" propagation="SUPPORTS"
    				read-only="true" />
    			<tx:method name="select*" propagation="SUPPORTS"
    				read-only="true" />
    			<tx:method name="get*" propagation="SUPPORTS"
    				read-only="true" />
    		</tx:attributes>
    	</tx:advice>
    	<!-- 切面 -->
        <!-- 基于Aspectj AOP配置事务 -->
    	<aop:config>
    		<!-- 指定切入点为:定义在com.lwh.service包里的任意类的任意方法。 -->
    		<aop:advisor advice-ref="txAdvice"
    			pointcut="execution(* com.lwh.service.*.*(..))" />
    	</aop:config>
    

    @Transactional 注解的方式声明事务

    XML文件:

    <!-- Spring中,使用XML配置事务的三大步骤:
    	1.创建事务管理器
    	2.开启注解方式
    	3.在需要事务的方法上使用@Transactional使用注解(一般来说在Service层)
    	-->
    	
    	<!-- 1.事务管理器 -->
    	<bean id="transactionManager"
    		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    		<!-- 数据源 -->
    		<property name="dataSource" ref="dataSource" />
    	</bean>
    	<!-- 2.开启事务注解方式-->
    	<tx:annotation-driven transaction-manager="transactionManager"/>
    	
    	
    

    Service类:

    public class UserService {
    
        @Autowired
        UserMapper userMapper;
    
    	//isolation	事务的隔离度,默认值采用 DEFAULT。
    	//propagation	事务的传播行为,默认值为 REQUIRED。
        @Transactional(isolation= Isolation.DEFAULT,propagation = Propagation.REQUIRED)
        public void test(){
            dao.addUser();
            dao.updateUser();
        }
    
    }
    

    @Transactional 注解也可以添加到类级别上。当把@Transactional 注解放在类级别时,表示所有该类的公共方法都配置相同的事务属性信息。当类级别配置了@Transactional,方法级别也配置了@Transactional,应用程序会以方法级别的事务属性信息来管理事务,换言之,方法级别的事务属性信息会覆盖类级别的相关配置信息。

    正确的设置@Transactional 的 propagation 属性

    需要注意下面三种 propagation 可以不启动事务。本来期望目标方法进行事务管理,但若是错误的配置这三种 propagation,事务将不会发生回滚。

    1. TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
    2. TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
    3. TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。

    事务的7种传播行为:

    事务传播行为类型 说明
    PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
    PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
    PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。
    PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
    PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
    PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
    PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

    @Transactional 只能应用到 public 方法才有效

    只有@Transactional 注解应用到 public 方法,才能进行事务管理。这是因为在使用 Spring AOP 代理时,Spring 在调用 TransactionInterceptor 在目标方法执行前后进行拦截之前,DynamicAdvisedInterceptor(CglibAopProxy 的内部类)的的 intercept 方法或 JdkDynamicAopProxy 的 invoke 方法会间接调用 AbstractFallbackTransactionAttributeSource(Spring 通过这个类获取@Transactional 注解的事务属性配置属性信息)的 computeTransactionAttribute 方法。

    protected TransactionAttribute computeTransactionAttribute(Method method,
        Class<?> targetClass) {
            // Don't allow no-public methods as required.不允许使用非公共方法。
            if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
    return null;}
    

    避免 Spring 的 AOP 的自调用问题

    在 Spring 的 AOP 代理下,只有目标方法由外部调用,目标方法才由 Spring 生成的代理对象来管理,这会造成自调用问题。若同一类中的其他没有@Transactional 注解的方法内部调用有@Transactional 注解的方法,有@Transactional 注解的方法的事务被忽略,不会发生回滚。见代码展示。

    @Service
    public class OrderService {
        private void insert() {
    		insertOrder();
    	}
    	@Transactional
        public void insertOrder() {
            //insert log info
            //insertOrder
            //updateAccount
           }
    }
    

    insertOrder 尽管有@Transactional 注解,但它被内部方法 insert 调用,事务被忽略,出现异常事务不会发生回滚。
    上面的两个问题@Transactional 注解只应用到 public 方法和自调用问题,是由于使用 Spring AOP 代理造成的。为解决这两个问题,使用 AspectJ 取代 Spring AOP 代理。

  • 相关阅读:
    Oracle重建表索引及手工收集统计信息
    VirtualBox虚拟机安装MSDOS和MINIX2.0.0双系统
    odp.net以及oracle oledb安装
    Oralce常用维护命令
    Sales_item
    IBM MQ Reason 2538(MQRC_HOST_NOT_AVAILABLE) 错误原因一例
    Unable to create the store directory. (Exception from HRESULT: 0x80131468)
    WMS函数组:13.WMS入库BAPI
    WMS函数组:12.批量入库物料移动凭证
    WMS函数组:11.交货单取金额
  • 原文地址:https://www.cnblogs.com/lwhsummer/p/11204199.html
Copyright © 2011-2022 走看看