Spring事务传播特性实例解析(以及如何使用注解形式事务)

原创 2015年11月19日 13:46:56

原文地址:http://blog.csdn.net/yoara/article/details/16114853
原文地址的文章,写的demo会误导读者,所以在原文地址文章的基础上对原作者的demo进行修改,让demo浅显易懂。

Demo说明

采用Junit4.10.0+Spring4.2.0+Spring JDBCTemplate+mysql5.1.51(数据库表的存储引擎使用 InnoDB,MyISAM存储引擎是不支持事务的),通过注解方式配置事务,代码层次包括主测试类,两个Service对象,事务在Service开启。

事务概念

注意:从原文地址中,COPY 过来的。
本地事务
数据库事务,默认事务为自动提交,因此如果一个业务逻辑类中有多次数据库操作将无法保证事务的一致性。

Spring事务
对本地事务操作的一次封装,相当于把使用JDBC代码开启、提交、回滚事务进行了封装。
上述两个概念会在demo中用到,以方便大家理解代码。

传播特性
该特性是保证事务是否开启,业务逻辑是否使用同一个事务的保证。当事务在传播过程中会受其影响。其传播特性包括:
1、Propagation.REQUIRED
方法被调用时自动开启事务,在事务范围内使用则使用同一个事务,否则开启新事务。
2、Propagation.REQUIRES_NEW
无论何时自身都会开启事务
3、Propagation.SUPPORTS
自身不会开启事务,在事务范围内则使用相同事务,否则不使用事务
4、Propagation.NOT_SUPPORTED
自身不会开启事务,在事务范围内使用挂起事务,运行完毕恢复事务
5、Propagation.MANDATORY
自身不开启事务,必须在事务环境使用否则报错
6、Propagation.NEVER
自身不会开启事务,在事务范围使用抛出异常
7、Propagation.NESTED
如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行。需要JDBC3.0以上支持。

代码实例

代码说明,两个 实例类,InsertPassword 、 InsertUser, InsertPassword类中的insertPassWord方法 调用了 InsertUser类中的 insertUser 方法。

测试代码

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.sky.lp.AAtestTransaction.InsertPassword;

public class TestJunit {
    @Test
    public void testTransaction() {
        ApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-servlet.xml");
        InsertPassword t  = (InsertPassword)appCtx.getBean("insertPassword");
        t.insertPassWord();
    }

}

InsertPassword类代码

package com.sky.lp.AAtestTransaction;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Component
public class InsertPassword {

    @Autowired
    private JdbcTemplate jdbc;

    @Autowired
    private InsertUser insertUser;

    @Transactional(propagation = Propagation.REQUIRED)
    public void insertPassWord() {
        String[] sql = new String[2];
        sql[0] = "INSERT INTO PASSWORD (USERID, PASSWORD, CREATE_TIME)  VALUES  ('1','qwe', now())";
        jdbc.execute(sql[0]);
        insertUser.insertUser();
        throw new RuntimeException("抛错");
    }

}

InsertUser类代码

package com.sky.lp.AAtestTransaction;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Component
public class InsertUser {

    @Autowired
    private JdbcTemplate jdbc;

    @Transactional(propagation = Propagation.REQUIRED)
    public void insertUser() {
        String[] sql = new String[2];
        sql[0] = "INSERT INTO user (name, age, CREATE_TIME) VALUES  ('123456789','25', now())";
        jdbc.execute(sql[0]);
    }

}

spring-servlet.xml 配置文件

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

    <!-- 启动包扫描功能,以便注册带有@Controller、@Service、@repository、@Component等注解的类成为spring的bean -->
    <context:annotation-config />
    <context:component-scan base-package="com.sky.lp.AAtestTransaction" />

    <!-- 定义数据源 使用 c3po 包 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
        init-method="init" destroy-method="close">
        <property name="name" value="druidOne" />
        <property name="url" value="jdbc:mysql://localhost:3306/littledemo" />
        <property name="username" value="root" />
        <property name="password" value="laixu785^@#"></property>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="initialSize" value="2" />
        <property name="maxActive" value="10" />
        <property name="minIdle" value="5" />
        <property name="validationQuery" value="SELECT COUNT(*) FROM DUAL" />
        <property name="testWhileIdle" value="true" />
        <property name="timeBetweenEvictionRunsMillis" value="5000" />
    </bean>

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

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

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

</beans>

传播特性 Propagation.REQUIRED

在 InsertPassword类中的insertPassWord方法 上 添加@Transactional(propagation = Propagation.REQUIRED)。在 InsertUser类中的insertUser方法 上 添加@Transactional(propagation = Propagation.REQUIRED)。

经测试无论在insertPassWord方法还是insertUser方法,如果有一个方法抛出运行时异常,数据提交失败。 这说明insertPassWord和insertUser使用的是同一个事务,并且只要方法被调用就开启事务。

传播特性 Propagation.REQUIRES_NEW

在 InsertPassword类中的insertPassWord方法 上 添加@Transactional(propagation = Propagation.REQUIRES_NEW)。在 InsertUser类中的insertUser方法 上 添加@Transactional(propagation = Propagation.REQUIRES_NEW)。

经测试无论在insertPassWord方法还是insertUser方法,如果其中一个方法抛出运行时异常,不会影响另一个方法事务的数据提交。 这说明insertPassWord和insertUser使用的是不的同事务。

传播特性 Propagation.SUPPORTS

在 InsertPassword类中的insertPassWord方法 上 添加@Transactional(propagation = Propagation.SUPPORTS)。在 InsertUser类中的insertUser方法 上 添加@Transactional(propagation = Propagation.SUPPORTS)。

经测试如果在insertPassWord中抛出异常,password数据和user数据都被正确提交。说明insertPassWord和insertUser没有被spring管理和开启事务,而是使用了本地事务,由于本地事务默认自动提交因此数据都提交成功,但它们使用的却不是同一个事务,一旦出现异常将导致数据的不一致。

传播特性 Propagation.NOT_SUPPORTED

在 InsertPassword类中的insertPassWord方法 上 添加@Transactional(propagation = Propagation.REQUIRED)。在 InsertUser类中的insertUser方法 上 添加@Transactional(propagation = Propagation.NOT_SUPPORTED)。

方法 insertPassWord 注释掉 抛错代码,insertUser 在方法末尾 添加

throw new RuntimeException("抛错");

经测试如果在insertUser 中抛出异常,passwrod数据提交失败,user数据提交成功。说明insertPassWord开启了事务,insertUser没有开启事务,而是使用了本地事务。

传播特性 Propagation.MANDATORY

在 InsertPassword类中的insertPassWord方法 上 添加@Transactional(propagation = Propagation.SUPPORTS)。在 InsertUser类中的insertUser方法 上 添加@Transactional(propagation = Propagation.MANDATORY)。

insertPassWord 方法 和 insertUser 方法 都注释掉 抛错 代码

经测试报错

org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'

说明 方法 insertUser 必须在事务内执行。

传播特性 Propagation.NEVER

在 InsertPassword类中的insertPassWord方法 上 添加@Transactional(propagation = Propagation.REQUIRED)。在 InsertUser类中的insertUser方法 上 添加@Transactional(propagation = Propagation.NEVER)。

insertPassWord 方法 和 insertUser 方法 都注释掉 抛错 代码

经测试报错

org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'

说明 方法 insertUser 不能在事务内执行。

传播特性 Propagation.NESTED

在 InsertPassword类中的insertPassWord方法 上 添加@Transactional(propagation = Propagation.NESTED)。在 InsertUser类中的insertUser方法 上 添加@Transactional(propagation = Propagation.NESTED)。

方法 insertPassWord在方法末尾添加

throw new RuntimeException("抛错");

经测试代码报错,user数据和password数据都没有提交成功。说明其按照REQUIRED特性运行。对于嵌套事务,大家可以模拟两个数据源,一方的失败不会影响另一方。

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

Spring事务传播特性的浅析——事务方法嵌套调用的迷茫

Spring事务传播机制回顾     Spring事务一个被讹传很广说法是:一个事务方法不应该调用另一个事务方法,否则将产生两个事务。结果造成开发人员在设计事务方法时束手束脚,生怕一不小心就...

Spring事物隔离级别以及事物的七种传播特性详细介绍,以及应用当中需要注意的点

使用步骤: 步骤一、在spring配置文件中引入命名空间  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xmlns:tx="...

spring 配置事务传播特性

       同事帮忙的解释: -...

spring学习笔记(一)事务的管理和传播特性

spring事务管理    以前没有Spring帮助我们完成事务的时候我们必须自己手动的控制事务,例如当我们项目中仅仅使用hibernate,而没有集成进spring的时候,我们在一个servic...

spring的AOP简介与事务传播特性总结

spring用到的另外一项技术就是AOP(Aspect-Oriented Programming, 面向切面编程),它是一种新的方法论, 是对传统 OOP(Object-Oriented Progra...

Spring事务传播特性实例解析

背景介绍         目前系统正在进行代码重构前期预研工作,目标采用spring控制事务以减少开发代码量,提高开发效率。同时避免开发人员编码控制事务所带来的链接没有释放,事务没有提交,出现异常事务...

spring事务的传播特性

Spring 事务一个被讹传很广说法是:一个事务方法不应该调用另一个事务方法,否则将产生两个事务。结果造成开发人员在设计事务方法时束手束脚,生怕一不小心就踩到地雷。 其实这种是不认识 Spring ...

Spring事务传播特性实例解析

背景介绍         目前系统正在进行代码重构前期预研工作,目标采用spring控制事务以减少开发代码量,提高开发效率。同时避免开发人员编码控制事务所带来的链接没有释放,事务没有提交,出现异常事...

Spring事务传播特性解析

  • 2013-11-05 01:00
  • 8.20MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)