Spring第十篇【事务配置】

以xml的方式

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd
                           http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd">

    <context:component-scan base-package="com.example.demo"/>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="druid"/>
    </bean>

    <context:property-placeholder location="classpath:jdbc.properties"/>

    <bean id="druid" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--配置平台事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="druid"/>
    </bean>

    <!--配置事务传播性,隔离级别以及超时回滚等问题 -->
    <!--transaction-manager默认值为transactionManager -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
    <!-- tx:method的属性:
          * name 是必须的,表示与事务属性关联的方法名(业务方法名),对切入点进行细化。通配符(*)可以用来指定一批关联到相同的事务属性的方法。
                    如:'get*'、'handle*'、'on*Event'等等.
          * propagation  不是必须的 ,默认值是REQUIRED 
                            表示事务传播行为, 包括REQUIRED,SUPPORTS,MANDATORY,REQUIRES_NEW,NOT_SUPPORTED,NEVER,NESTED
          * isolation    不是必须的 默认值DEFAULT 
                            表示事务隔离级别(数据库的隔离级别) 
          * timeout      不是必须的 默认值-1(永不超时)
                            表示事务超时的时间(以秒为单位) 
          
          * read-only    不是必须的 默认值false不是只读的 
                            表示事务是否只读 
          
          * rollback-for 不是必须的   
                            表示将被触发进行回滚的 Exception(s);以逗号分开。
                            如:'com.foo.MyBusinessException,ServletException' 
          
          * no-rollback-for 不是必须的  
                              表示不被触发进行回滚的 Exception(s);以逗号分开。
                              如:'com.foo.MyBusinessException,ServletException'
                                            
     -->
            <tx:method name="del*"/>
            <tx:method name="update*"/>
            <tx:method name="add*"/>
            <tx:method name="*" rollback-for="Exception" />
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* com.example.demo.service.impl.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
    </aop:config>

</beans>

以注解的方式

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd
                           http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd">

    <context:component-scan base-package="com.example.demo"/>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="druid"/>
    </bean>

    <context:property-placeholder location="classpath:jdbc.properties"/>

    <bean id="druid" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--配置平台事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="druid"/>
    </bean>

    <!--开启注解驱动-->
    <tx:annotation-driven transaction-manager="transactionManager"/>

</beans>
package com.example.demo.service.impl;

import com.example.demo.dao.AccountDao;
import com.example.demo.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountDao accountDao;

    @Override
    @Transactional
    public void transfer(String name, String name2, int money) {
        accountDao.transferOut(name,money);
        accountDao.transferIn(name2,money);
    }
}

传播级别

  1. PROPAGATION_REQUIRED: 如果存在一个事务,则支持当前事务。如果没有事务则开启
  2. PROPAGATION_SUPPORTS: 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行
  3. PROPAGATION_MANDATORY: 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常
  4. PROPAGATION_REQUIRES_NEW: 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起
  5. PROPAGATION_NOT_SUPPORTED: 总是非事务地执行,并挂起任何存在的事务。
  6. PROPAGATION_NEVER: 总是非事务地执行,如果存在一个活动事务,则抛出异常
  7. PROPAGATION_NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行

隔离级别

  1. ISOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别,另外四个与JDBC的隔离级别相对应
  2. ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据,这种隔离级别会产生脏读,不可重复读和幻像读
  3. ISOLATION_READ_COMMITTED: 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据
  4. ISOLATION_REPEATABLE_READ: 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读,它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了
    避免下面的情况产生(不可重复读)
  5. ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行,除了防止脏读,不可重复读外,还避免了幻像读

声明式事务回滚的原理

当被切面切中或者是加了注解的方法中抛出了RuntimeException异常时,Spring会进行事务回滚。默认情况下是捕获到方法的RuntimeException异常,也就是说抛出只要属于运行时的异常(即RuntimeException及其子类)都能回滚;但当抛出一个不属于运行时异常时,事务是不会回滚的。

总结:

  1. Spring碰到error一定会回滚

  2. Spring事务管理是根据Unchecked Exception来进行回滚操作

  3. Spring框架下,所有SQL异常都被org.springframework重写为RuntimeException,事务因此也会发生回滚

  4. 配置rollback-for="Exception"时,Spring遇到RuntimeException和非RuntimeException都会回滚

posted @ 2020-08-20 10:55  幻竹  阅读(180)  评论(0)    收藏  举报