Spring事务管理配置示例

一.Spring事务特性

事务(Transaction)是并发控制的单元,是用户定义的一组操作序列。从数据库角度,就是一组SQL指令,如果执行过程中没有错误,则全部执行成功;如果执行出现错误,则撤销执行过的所有指令。Spring事务管理功能是基于底层DBMS本身的事务处理机制实现。

1.事务隔离级别
  隔离级别是指若干个并发的事务之间的隔离程度
  ISOLATION_DEFAULT:默认值,使用数据库的默认隔离级别,就是ISOLATION_READ_COMMITTED。
  ISOLATION_READ_UNCOMMITTED:表示一个事务可以读取另一个事务修改但还没有提交的数据。不能防止脏读,不可重复读和幻读,很少使用该隔离级别。
  ISOLATION_READ_COMMITTED:表示一个事务只能读取另一个事务已经提交的数据。可以防止脏读。
  ISOLATION_REPEATABLE_READ:表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。可以防止脏读和不可重复读。
  ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,可以防止脏读、不可重复读以及幻读。严重影响程序的性能,通常不会用到该级别。

2.事务传播行为
  所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为
  PROPAGATION_REQUIRED:默认值,如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
  PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
  PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
  PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
  PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则等价于PROPAGATION_REQUIRED。

3.事务超时
  所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。默认设置为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那么就是none,没有超时限制。

4.事务只读属性
  只读事务用于客户代码只读但不修改数据的情形,只读事务用于特定情景下的优化。

二.方法一(基于@Transactional注解的事务)

 支持@Transactional注解,编辑resources/spring/applicationContext_database.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: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/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">

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

    <!-- 支持@Transactional注解事务,proxy-target-class=true通过CGlib创建子类来代理业务类 -->
    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
</beans>

UserServiceImpl增加@Transactional注解,编辑service/impl/UserServiceImpl.java

@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserDOMapper userDao;

    @Transactional(value = "transactionManager", propagation = Propagation.REQUIRED)
    public Boolean init() {

        UserDO A = new UserDO();
        A.setUsername("Apple");
        A.setPassword("123456");
        userDao.insert(A);

        if (true) {
            throw new RuntimeException("SQL Exception");
        }

        UserDO B = new UserDO();
        B.setUsername("Amazon");
        B.setPassword("abcdef");
        userDao.insert(B);

        return true;
    }
}

三.方法二(基于aop的事务,通过aop/tx命名空间配置事务)

Maven导入aop依赖,编辑pom.xml

        <!-- aop事务 -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.11</version>
        </dependency>

为service包下的init*()方法增加aop切面,编辑resources/spring/applicationContext_database.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:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

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

    <!-- 事务advice -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!-- 与事务关联的方法名 -->
            <tx:method name="init*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!-- 通过aop定义事务切面 -->
    <aop:config>
        <aop:pointcut id="serviceMethod" expression="execution(* com.learn.spring.server.service..*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod"/>
    </aop:config>
</beans>

 四.验证事务

通过日志信息确认当UserServiceImpl.init()方法抛出RuntimeException时, 数据库执行了rollback()回滚。登录数据库,查询表中记录,证实记录未写入数据库,事务配置已生效。


作者:faramita2016
出处:http://www.cnblogs.com/faramita2016/
本文采用知识共享署名-非商业性使用-相同方式共享 3.0 中国大陆许可协议进行许可,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
原文地址:https://www.cnblogs.com/faramita2016/p/7635165.html