spring事务传播机制实例讲解

合集下载

spring事务传播行为详解

spring事务传播行为详解

spring事务传播⾏为详解地址:⼀、什么是事务的传播?简单的理解就是多个事务⽅法相互调⽤时,事务如何在这些⽅法间传播。

举个栗⼦,⽅法A是⼀个事务的⽅法,⽅法A执⾏过程中调⽤了⽅法B,那么⽅法B有⽆事务以及⽅法B对事务的要求不同都会对⽅法A的事务具体执⾏造成影响,同时⽅法A的事务对⽅法B的事务执⾏也有影响,这种影响具体是什么就由两个⽅法所定义的事务传播类型所决定。

⼆、Spring事务传播类型枚举Propagation介绍在Spring中对于事务的传播⾏为定义了七种类型分别是:REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER、NESTED。

在Spring源码中这七种类型被定义为了枚举。

源码在org.springframework.transaction.annotation包下的Propagation,源码中注释很多,对传播⾏为的七种类型的不同含义都有解释,后⽂中锤⼦我也会给⼤家分析,我在这⾥就不贴所有的源码,只把这个类上的注解贴⼀下,翻译⼀下就是:表⽰与TransactionDefinition接⼝相对应的⽤于@Transactional注解的事务传播⾏为的枚举。

也就是说枚举类Propagation是为了结合@Transactional注解使⽤⽽设计的,这个枚举⾥⾯定义的事务传播⾏为类型与TransactionDefinition 中定义的事务传播⾏为类型是对应的,所以在使⽤@Transactional注解时我们就要使⽤Propagation枚举类来指定传播⾏为类型,⽽不直接使⽤TransactionDefinition接⼝⾥定义的属性。

在TransactionDefinition接⼝中定义了Spring事务的⼀些属性,不仅包括事务传播特性类型,还包括了事务的隔离级别类型(事务的隔离级别后⾯⽂章会详细讲解),更多详细信息,⼤家可以打开源码⾃⼰翻译⼀下⾥⾯的注释package org.springframework.transaction.annotation;import org.springframework.transaction.TransactionDefinition;/*** Enumeration that represents transaction propagation behaviors for use* with the {@link Transactional} annotation, corresponding to the* {@link TransactionDefinition} interface.** @author Colin Sampaleanu* @author Juergen Hoeller* @since 1.2*/public enum Propagation {...}三、七种事务传播⾏为详解与⽰例在介绍七种事务传播⾏为前,我们先设计⼀个场景,帮助⼤家理解,场景描述如下现有两个⽅法A和B,⽅法A执⾏会在数据库ATable插⼊⼀条数据,⽅法B执⾏会在数据库BTable插⼊⼀条数据,伪代码如下://将传⼊参数a存⼊ATablepubilc void A(a){insertIntoATable(a);}//将传⼊参数b存⼊BTablepublic void B(b){insertIntoBTable(b);}接下来,我们看看在如下场景下,没有事务,情况会怎样public void testMain(){A(a1); //调⽤A⼊参a1testB(); //调⽤testB}public void testB(){B(b1); //调⽤B⼊参b1throw Exception; //发⽣异常抛出B(b2); //调⽤B⼊参b2}在这⾥要做⼀个重要提⽰:Spring中事务的默认实现使⽤的是AOP,也就是代理的⽅式,如果⼤家在使⽤代码测试时,同⼀个Service类中的⽅法相互调⽤需要使⽤注⼊的对象来调⽤,不要直接使⽤this.⽅法名来调⽤,this.⽅法名调⽤是对象内部⽅法调⽤,不会通过Spring代理,也就是事务不会起作⽤以上伪代码描述的⼀个场景,⽅法testMain和testB都没有事务,执⾏testMain⽅法,那么结果会怎么样呢?相信⼤家都知道了,就是a1数据成功存⼊ATable表,b1数据成功存⼊BTable表,⽽在抛出异常后b2数据存储就不会执⾏,也就是b2数据不会存⼊数据库,这就是没有事务的场景。

Spring事务隔离级别与传播机制详解,spring+mybatis+atomikos实现。。。

Spring事务隔离级别与传播机制详解,spring+mybatis+atomikos实现。。。

Spring事务隔离级别与传播机制详解,spring+mybatis+atomikos实现。

原创说明:本⽂为本⼈原创作品,绝⾮他处转载,转账请注明出处1.事务的定义:事务是指多个操作单元组成的合集,多个单元操作是整体不可分割的,要么都操作不成功,要么都成功。

其必须遵循四个原则(ACID)。

1. 原⼦性(Atomicity):即事务是不可分割的最⼩⼯作单元,事务内的操作要么全做,要么全不做;2. ⼀致性(Consistency):在事务执⾏前数据库的数据处于正确的状态,⽽事务执⾏完成后数据库的数据还是应该处于正确的状态,即数据完整性约束没有被破坏;如银⾏转帐,A转帐给B,必须保证A的钱⼀定转给B,⼀定不会出现A的钱转了但B没收到,否则数据库的数据就处于不⼀致(不正确)的状态。

3. 隔离性(Isolation):并发事务执⾏之间互不影响,在⼀个事务内部的操作对其他事务是不产⽣影响,这需要事务隔离级别来指定隔离性;4. 持久性(Durability):事务⼀旦执⾏成功,它对数据库的数据的改变必须是永久的,不会因⽐如遇到系统故障或断电造成数据不⼀致或丢失。

2.事务的类型1. 数据库分为本地事务跟全局事务本地事务:普通事务,独⽴⼀个数据库,能保证在该数据库上操作的ACID。

分布式事务:涉及两个或多个数据库源的事务,即跨越多台同类或异类数据库的事务(由每台数据库的本地事务组成的),分布式事务旨在保证这些本地事务的所有操作的ACID,使事务可以跨越多台数据库;2. Java事务类型分为JDBC事务跟JTA事务JDBC事务:即为上⾯说的数据库事务中的本地事务,通过connection对象控制管理。

JTA事务:JTA指Java事务API(Java Transaction API),是Java EE数据库事务规范, JTA只提供了事务管理接⼝,由应⽤程序服务器⼚商(如WebSphereApplication Server)提供实现,JTA事务⽐JDBC更强⼤,⽀持分布式事务。

Spring事物的传播特性详解

Spring事物的传播特性详解

Spring事物的传播特性详解⽬录⼀、事务的传播性⼆、测试前准备2.1、准备好数据库表2.2、初始化spring项⽬2.3、数据库连接信息配置2.4、Service、Dao2.5、测试类2.6、说明三、使⽤其他传播性3.1、REQUIRES_NEW3.2、MANDATORY3.3、SUPPORTS3.4、NOT_SUPPORTED3.5、NEVER3.6、NESTED⼀、事务的传播性研究的是多个事务存在时的处理策略1)REQUIRED:如果存在⼀个事务,则⽀持当前事务,如果当前没有事务,就新建⼀个事务。

这是最常见的选择。

2)SUPPORTS:如果存在⼀个事务,⽀持当前事务,如果当前没有事务,就以⾮事务⽅式执⾏。

3)MANDATORY:如果存在⼀个事务,⽀持当前事务,如果当前没有事务,就抛出异常。

4)REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。

5)NOT_SUPPORTED:以⾮事务⽅式执⾏操作,如果当前存在事务,就把当前事务挂起。

6)NEVER:以⾮事务⽅式执⾏,如果当前存在事务,则抛出异常。

7)NESTED:⽀持当前事务,新增Savepoint点,与当前事务同步提交或回滚。

⼆、测试前准备2.1、准备好数据库表数据库transaction_propagation账号表account、书本表book、库存表book_stockSET NAMES utf8mb4;SET FOREIGN_KEY_CHECKS = 0;-- ------------------------------ Table structure for account-- ----------------------------DROP TABLE IF EXISTS `account`;CREATE TABLE `account` (`user_id` int(11) NOT NULL AUTO_INCREMENT,`user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`balance` double(11, 2) UNSIGNED NULL DEFAULT NULL,PRIMARY KEY (`user_id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic STORAGE MEMORY; -- ------------------------------ Records of account-- ----------------------------INSERT INTO `account` VALUES (1, 'Albert', 100.00);-- ------------------------------ Table structure for book-- ----------------------------DROP TABLE IF EXISTS `book`;CREATE TABLE `book` (`book_id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,`price` double(11, 2) UNSIGNED NULL DEFAULT NULL,PRIMARY KEY (`book_id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 1003 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; -- ------------------------------ Records of book-- ----------------------------INSERT INTO `book` VALUES (1001, '基础数据结构', 60.00);INSERT INTO `book` VALUES (1002, '数据库设计', 50.00);-- ------------------------------ Table structure for book_stock-- ----------------------------DROP TABLE IF EXISTS `book_stock`;CREATE TABLE `book_stock` (`book_id` int(11) NOT NULL AUTO_INCREMENT,`stock` int(11) UNSIGNED NULL DEFAULT NULL,PRIMARY KEY (`book_id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 1003 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; -- ------------------------------ Records of book_stock-- ----------------------------INSERT INTO `book_stock` VALUES (1001, 100);INSERT INTO `book_stock` VALUES (1002, 100);SET FOREIGN_KEY_CHECKS = 1;2.2、初始化spring项⽬导⼊⼀些基本依赖包:jdbc、mysql驱动包、测试模块;<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>2.3、数据库连接信息配置#jdbcspring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost/transaction_propagation?useUnicode=true&characterEncoding=utf-8username: rootpassword: 1234562.4、Service、Dao这⾥只使⽤测试调⽤,省略controller以及entity等层构;1、⾸先Dao类,编写⼀个购买的简单操作:查询单价、更新库存、更新账户余额;@Repositorypublic class BookShopDao {@Autowiredprivate JdbcTemplate jdbcTemplate = new JdbcTemplate();public double getPriceById(Integer bookId) {String sql = "SELECT price FROM BOOK WHERE book_id = ?";double price = jdbcTemplate.query(sql, new PreparedStatementSetter() {@Overridepublic void setValues(PreparedStatement preparedStatement) throws SQLException {preparedStatement.setInt(1, bookId);}}, new ResultSetExtractor<Double>() {@Overridepublic Double extractData(ResultSet resultSet) throws SQLException, DataAccessException {double p = 0.0;while (resultSet.next()) {p = resultSet.getDouble("price");}return p;}});return price;}public void updateBookStock(Integer bookId, int num) {String sql = "UPDATE book_stock SET stock = stock - ? WHERE book_id = ?";jdbcTemplate.update(sql, new PreparedStatementSetter() {@Overridepublic void setValues(PreparedStatement preparedStatement) throws SQLException {preparedStatement.setInt(1, num);preparedStatement.setInt(2, bookId);}});}public void updateBalance(Integer userId, double balance) {//修改⾦额String sql = "UPDATE account SET balance = balance - ? WHERE user_id = ?";jdbcTemplate.update(sql, new PreparedStatementSetter() {@Overridepublic void setValues(PreparedStatement preparedStatement) throws SQLException {preparedStatement.setDouble(1, balance);preparedStatement.setInt(2, userId);}});}}2、研究事务传播学性其实就是研究两个以上的事务在嵌套时的应⽤⽅式,所以这⾥需要写两个Service进⾏嵌套调⽤;接⼝类此处省略BookShopServiceImpl 中的purchase⽤@Transactional是指⼀个购买单进来必须保证(1、2、3)的原⼦性;@Servicepublic class BookShopServiceImpl implements BookShopService {@Autowiredprivate BookShopDao bookShopDao;@Transactional@Overridepublic void purchase(Integer userId,Integer bookId,int num){//1、获取要购买的图书价格double price = bookShopDao.getPriceById(bookId);//2、更新图书库存bookShopDao.updateBookStock(bookId,num);//3、更新⽤户余额bookShopDao.updateBalance(userId,price*num);}}CashierServiceImpl 中buy⽅法中的@Transactional是指⼀个订单中出现多个购买单进来必须保证的原⼦性;因为⼀个订单可能包含⼏种商品的购买。

Spring中的事务管理实例详解

Spring中的事务管理实例详解

Spring中的事务管理实例详解本文实例讲述了Spring中的事务管理。

分享给大家供大家参考。

具体分析如下:事务简介:事务管理是企业级应用程序开发中必不可少的技术,用来确保数据的完整性和一致性事务就是一系列的动作,它们被当作一个单独的工作单元。

这些动作要么全部完成,要么全部不起作用事务的四个关键属性(ACID)①原子性(atomicity):事务室一个原子操作,有一系列动作组成。

事务的原子性确保动作要么全部完成,要么完全不起作用②一致性(consistency):一旦所有事务动作完成,事务就被提交。

数据和资源就处于一种满足业务规则的一致性状态中③隔离性(isolation):可能有许多事务会同时处理相同的数据,因此每个事物都应该与其他事务隔离开来,防止数据损坏④持久性(durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响。

通常情况下,事务的结果被写到持久化存储器中Spring中的事务管理作为企业级应用程序框架,Spring在不同的事务管理API之上定义了一个抽象层。

而应用程序开发人员不必了解底层的事务管理API,就可以使用Spring的事务管理机制。

Spring既支持编程式事务管理,也支持声明式的事务管理编程式事务管理:将事务管理代码嵌入到业务方法中来控制事务的提交和回滚,在编程式事务中,必须在每个业务操作中包含额外的事务管理代码声明式事务管理:大多数情况下比编程式事务管理更好用。

它将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。

事务管理作为一种横切关注点,可以通过AOP方法模块化。

Spring通过Spring AOP框架支持声明式事务管理。

Spring事务的传播属性:当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。

例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。

事务的传播行为可以由传播属性指定。

Spring定义了7种传播行为:Spring支持的事务传播行为传播行为含义PROPAGATION_MANDATORY 表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常PROPAGATION_NESTED 表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。

事务的传播机制

事务的传播机制

事务的传播机制1.什么是事务: 事务是程序中⼀系列严密的操作,所有操作执⾏必须成功完成,否则在每个操作所做的更改将会被撤销,这也是事务的原⼦性(要么成功,要么失败)。

数据库向⽤户提供保存当前程序状态的⽅法,叫事务提交(commit);当事务执⾏过程中,使数据库忽略当前的状态并回到前⾯保存的状态的⽅法叫事务回滚(rollback)2.事务的传播机制 以spring的事务传播机制为例⼦: Spring事务机制主要包括声明式事务和编程式事务,此处侧重讲解声明式事务,编程式事务在实际开发中得不到⼴泛使⽤,仅供学习参考。

Spring声明式事务让我们从复杂的事务处理中得到解脱。

使得我们再也⽆需要去处理获得连接、关闭连接、事务提交和回滚等这些操作。

再也⽆需要我们在与事务相关的⽅法中处理⼤量的try…catch…finally代码。

我们在使⽤Spring声明式事务时,有⼀个⾮常重要的概念就是事务属性。

事务属性通常由事务的传播⾏为,事务的隔离级别,事务的超时值和事务只读标志组成。

我们在进⾏事务划分时,需要进⾏事务定义,也就是配置事务的属性。

spring在TransactionDefinition接⼝中定义了七个事务传播⾏为:propagation_requierd:如果当前没有事务,就新建⼀个事务,如果已存在⼀个事务中,加⼊到这个事务中,这是最常见的选择。

propagation_supports:⽀持当前事务,如果没有当前事务,就以⾮事务⽅法执⾏。

propagation_mandatory:使⽤当前事务,如果没有当前事务,就抛出异常。

propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。

propagation_not_supported:以⾮事务⽅式执⾏操作,如果当前存在事务,就把当前事务挂起。

propagation_never:以⾮事务⽅式执⾏操作,如果当前事务存在则抛出异常。

Spring事务管理中的七种传播机制及示例讲解

Spring事务管理中的七种传播机制及示例讲解

Spring事务管理中的七种传播机制及⽰例讲解课程分组的时候分到了Spring传播机制的内容,研究整理了⼀下。

⼀、事务传播⾏为和事务传播机制事务传播⾏为:⼀般发⽣在事务嵌套的场景中,⽐如⼀个有事务的⽅法⾥⾯调⽤了另外⼀个有事务的⽅法这个时候就会产⽣事务边界控制的问题,即两个⽅法是各⾃作为独⽴的事务提交还是内层的事务合并到外层的事务⼀起提交Spring规定了七⼤传播机制来解决边界控制的问题。

⼆、七⼤传播机制传播机制说明PROPAGATION_REQUIRED如果当前没有事务,就新建⼀个事务,如果已经存在⼀个事务中,加⼊到这个事务中。

这是最常见的选择。

PROPAGATION_SUPPORTS⽀持当前事务,如果当前没有事务,就以⾮事务⽅式执⾏。

PROPAGATION_MANDATORY使⽤当前的事务,如果当前没有事务,就抛出异常。

PROPAGATION_REQUIRES_NEW新建事务,如果当前存在事务,把当前事务挂起。

PROPAGATION_NOT_SUPPORTED以⾮事务⽅式执⾏操作,如果当前存在事务,就把当前事务挂起。

PROPAGATION_NEVER以⾮事务⽅式执⾏,如果当前存在事务,则抛出异常。

PROPAGATION_NESTED如果当前存在事务,则在嵌套事务内执⾏。

如果当前没有事务,则执⾏与PROPAGATION_REQUIRED类似的操作。

三、对⽐理解及举例第⼀组传播机制通俗解释PROPAGATION_NEVER强制以⾮事务的⽅式运⾏,外层有事务,将会产⽣异常PROPAGATION_MANDATORY强制加⼊外层事务,外层没有事务,则会产⽣异常举例:在充值处理这个业务中,调⽤了扣款和订单⽣成两个⽅法,充值处理业务需要扣款操作和订单⽣成操作同成功或者失败,所以需要把这两个⽅法放到同⼀个事务中运⾏;所以可以指定这两个⽅法的传播机制为MANDATORY,这样它们就会都加⼊到外层事务,处于⼀个事务中,可以保证同成功或失败。

「聊一聊Spring」Spring的事务传播行为

「聊一聊Spring」Spring的事务传播行为

「聊⼀聊Spring 」Spring 的事务传播⾏为Spring中的事务传播⾏为事务管理并⾮ Spring ⾸创,Spring 也借鉴了很多其他的框架,然后加以统⼀。

在 Spring 中,我们经常使⽤声明式事务,在⽅法或类上添加 Spring 的 @Transtional 注解,在这个注解中我们可以指定事务传播⾏为,这个注解也参考了 EJB 的javax.ejb.TransactionAttribute 以及 JTA 的 javax.transaction.Transactional,这⾥先通过对⽐认识⼀下这三者的异同。

从上⾯的表格中可以看到,在 Spring 的 @Transactional 中都可以找到 EJB、JTA 注解中相应的参数。

事实上,Spring 也对 EJB 的 @TransactionAttribute 注解及 JTA 的@Transactional 加以了⽀持,在 Spring 中这三个注解都可以使⽤。

现在将重点转向事务传播⾏为,上⾯的三个注解都有事务传播⾏为,那么这三者的事务传播⾏为⼜有何异同呢?有没有发现⼀些问题?Spring 中的事务定义与 EJB、JTA 基本⼀致,它们名称不仅相同,事实上语义和实现也相似,⽽且 Spring 还增加了⼀个 NESTED 类型的事务传播⾏为。

事务传播⾏为主要是控制新⽅法执⾏时是否使⽤事务,如何处理线程中以存在的事务。

下⾯是对 Spring 中的这7中事务传播⾏为的描述:REQUIRED :默认的事务传播⾏为;需要事务:存在事务则使⽤已存在事务,否则创建新的事务;SUPPORTS :⽀持已存在事务:存在事务则使⽤已存在事务,否则以⾮事务⽅式运⾏;MANDATORY :强制使⽤事务:存在事务则使⽤已存在事务,否则抛出异常;REQUIRES_NEW :需要新事务:存在事务则挂起已存在事务,否则创建新事务;NOT_SUPPORTED :不⽀持事务:存在事务则挂起已存在事务,否则以⾮事务⽅式运⾏;NEVER :从不使⽤事务:存在事务则抛出异常,否则以⾮事务⽅式运⾏;NESTED :嵌套事务:存在事务则使创建保存点使⽤嵌套的事务,否则创建新的事务。

spring事务配置方式以及事务的传播性、隔离级别

spring事务配置方式以及事务的传播性、隔离级别

spring事务配置⽅式以及事务的传播性、隔离级别在前⾯的⽂章中总结了事务的5中配置⽅式,但是很多⽅式都不⽤⽽且当时的配置使⽤的所有参数都是默认的参数,这篇⽂章就看常⽤的两种事务配置⽅式并信息配置事务的传播性、隔离级别、以及超时等问题,废话不说下⾯就来看看!⼀、注解式事务1、注解式事务在平时的开发中使⽤的挺多,⼯作的两个公司中看到很多项⽬使⽤了这种⽅式,下⾯看看具体的配置demo。

2、事务配置实例(1)、spring+mybatis 事务配置[html]1. <!-- 定义事务管理器 -->2. <bean id="transactionManager"3. class="org.springframework.jdbc.datasource.DataSourceTransactionManager">4. <property name="dataSource" ref="dataSource" />5. </bean>6. <!--使⽤注释事务 -->7. <tx:annotation-driven transaction-manager="transactionManager" />(2)、spring+ 事务配置[html]1. <!-- 事务管理器配置,单数据源事务 -->2. <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">3. <property name="sessionFactory" ref="sessionFactory" />4. </bean>5.6. <!-- 使⽤annotation定义事务 -->7. <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />看到上⾯的这两段配置⽂件是不是很熟悉,对的这就是我们平时看到的事务的配置,在spring的配置中配置数据源即dataSource、事务管理器,事务管理器使⽤不同的orm框架事务管理器类就不同,⽐如这⾥使⽤的是mybatis 所以是[html]1. org.springframework.jdbc.datasource.DataSourceTransactionManager如果使⽤hibernate 则事务管理器类为[html]1. org.springframework.orm.hibernate3.HibernateTransactionManager这是使⽤注解⽅式时要配置的,代码中的具体的注解以及事务的传播性、隔离级别⼀般在service 层中配置下⾯看看3、@Transactional(1)、这⾥说明⼀下,有的把这个注解放在类名称上⾯了,这样你配置的这个@Transactional 对这个类中的所有public⽅法都起作⽤(2)、@Transactional ⽅法⽅法名上,只对这个⽅法有作⽤,同样必须是public的⽅法⽐如这⾥就对这个⽅法定义了⼀个事务同时设置了很多属性:[java]1. @Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class,timeout=1,isolation=Isolation.DEFAULT)2. public void saveUser(Map<String, String> map) throws Exception {3. System.out.println("⽅法开始");4. for (int i = 0; i < 500000; i++) {5. System.out.println("*");6. }7. System.out.println("进⼊保存");8. userDao.saveUser(map);9. System.out.println("退出保存");10. }4、事物配置中有哪些属性可以配置(1)、事务的传播性:@Transactional(propagation=Propagation.REQUIRED)如果有事务, 那么加⼊事务, 没有的话新建⼀个(默认情况下)(2)、事务的超时性:@Transactional(timeout=30) //默认是30秒注意这⾥说的是事务的超时性⽽不是Connection的超时性,这两个是有区别的(3)、事务的隔离级别:@Transactional(isolation = Isolation.READ_UNCOMMITTED)读取未提交数据(会出现脏读, 不可重复读) 基本不使⽤(4)、回滚:指定单⼀异常类:@Transactional(rollbackFor=RuntimeException.class)指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})该属性⽤于设置需要进⾏回滚的异常类数组,当⽅法中抛出指定异常数组中的异常时,则进⾏事务回滚。

浅谈Spring事务传播行为实战

浅谈Spring事务传播行为实战

浅谈Spring事务传播⾏为实战Spring框架提供了事务管理的标准实现,且可以通过注解或者XML⽂件的⽅式声明和配置事务。

通过异步事件的⽅式解耦服务调⽤,可以提⾼程序的响应速度,并且避免因为事务传播⾏为⽽导致的事务问题。

本⽂以⼀个电商平台包裹出库的业务为实际背景,通过异步事件与线程池的⽅式解耦嵌套事务,提⾼程序并发性能;为了便于问题的分析和⽅案的理解,同时还讲解了Spring的事务管理,并着重介绍了⼏种不同的事务传播⾏为。

事务⼩贴⼠什么是事务呢?简单来讲事务就是逻辑上的⼀组操作,这些操作要么都执⾏,要么都不执⾏。

什么是事务管理呢?所谓事务管理,其实就是“按照给定的事务规则来执⾏事务的提交或者回滚操作”。

事务的机制实现很⼤⼀部依赖事务⽇志⽂件(undo log和redo log)。

事务⽇志是⼀个与数据库⽂件分开的⽂件。

它存储对数据库进⾏的所有更改,并全部记录插⼊、更新、删除、提交、回退和数据库模式变化。

事务⽇志是备份和恢复的重要组件。

订单出库失败在订单的包裹出库之前,会将出库指令下发到商城,其中包含包裹寄送的快递信息,以便销售平台展⽰快递跟踪信息;同时,为了防⽌前端因为超卖或者重复下单等原因,已经将订单取消,会根据前端商城的返回状态判断订单是否可以出库。

其中,系统交互流程如下,在前端销售平台与WMS(仓储管理系统)之间,会有统⼀的OMS(订单管理系统)进⾏销售单的管理和数据中转。

当前端销售平台收到出库信息以后,会进⾏如下的校验与操作:为了防⽌调⽤通知服务的时候出现异常,影响包裹出库,调⽤通知服务的代码是⽤try-catch语句包裹起来的。

但是,某些订单在出库的时候,还是出现了如下异常,出库失败:org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-onlyat org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:873)at mit(AbstractPlatformTransactionManager.java:710)at mitTransactionAfterReturning(TransactionAspectSupport.java:534)at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:305)at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)根据事务的传播⾏为,Transaction rolled back because it has been marked as rollback-only应该是因为被调⽤的事务回滚了,当调⽤⼀⽅提交事务的时候因为被标记为了rollback-only,因此⽆法正常提交。

Spring事务传播机制

Spring事务传播机制

Spring事务传播机制 spring的管理的事务可以分为如下2类:逻辑事务:在spring中定义的事务通常指逻辑事务,提供⽐物理事务更抽象,⽅便的事务配置管理,但也基于物理事务物理事务:特定于数据库的事务 spring中⽀持⼀下2中事务声明⽅式编程式事务:当系统需要明确的,细粒度的控制各个事务的边界,应选择编程式事务声明式事务:当系统对于事务的控制粒度较粗时,应该选择申明式事 ⽆论你选择上述何种事务⽅式去实现事务控制,spring都提供基于门⾯设计模式的事务管理器供选择,如下是spring事务中⽀持的事务管理器UML结构图如下1.各种事务管理器的定义如下JdbcTransactionManager定义如下<bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource"ref="dataSource"/></bean>View Codehibernate事务管理器配置如下<bean id="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager"><property name="sessionFactory" ref="sessionFactory"/></bean>View Code hibernate的事务管理器会注⼊session会话⼯⼚,然后将事务处理委托给当前的transaction对象,事务提交时,调⽤commit()⽅法,回滚时调⽤rollback()⽅法.其余事务管理器可参见spring in action中说明。

Spring声明式事务@Transactional详解,事务隔离级别和传播行为

Spring声明式事务@Transactional详解,事务隔离级别和传播行为

Spring声明式事务@Transactional详解,事务隔离级别和传播⾏为@Transactional注解⽀持9个属性的设置,这⾥只讲解其中使⽤较多的三个属性:readOnly、propagation、isolation。

其中propagation属性⽤来枚举事务的传播⾏为,isolation⽤来设置事务隔离级别,readOnly进⾏读写事务控制。

@Service@Transactional(readOnly = true)public class AppTradeRec2Service extends BaseService {@Autowiredprivate AppTradeRecDao appTradeRecDao;@Autowiredprivate ConsInfoDao consInfoDao;@Transactional(readOnly = false)public void payCharge(TradeRec tradeRec) {User usr = UserUtils.getUser();ConsInfo cons = consInfoDao.getByUser(usr.getId());//修改交易记录tradeRec.setPayBefore(cons.getAccountAmt());tradeRec.setPayAfter(cons.getAccountAmt() - tradeRec.getRcvAmt());tradeRec.setIsPay("99");appTradeRecDao.save(tradeRec);//修改账户余额cons.setAccountAmt(cons.getAccountAmt() - tradeRec.getRcvAmt());consInfoDao.save(cons);}}⼀、readOnly读写事务控制readOnly=true表明所注解的⽅法或类只是读取数据。

Spring使用注解对事务控制详解与实例

Spring使用注解对事务控制详解与实例

Spring使⽤注解对事务控制详解与实例1.什么是事务⼀荣俱荣,⼀损俱损,很多复杂的操作我们可以把它看成是⼀个整体,要么同时成功,要么同时失败。

事务的四个特征ACID:原⼦性(Atomic):表⽰组成⼀个事务的多个数据库的操作的不可分割的单元,只有所有的操作成功才算成功,整个事务提交,其中任何⼀个操作失败了都是导致整个所有操作失败,事务会回滚。

⼀致性(Consistentcy):事务操作成功后,数据库所处的状态和业务规则⼀致。

如果A账户给B账户汇100,A账户减去100,B加上100,两个账户的总额是不变的。

隔离性(islation):在多个数据库的操作相同的数据并发时,不同的事务有⾃⼰的数据空间,事务与事务之间不受⼲扰(不是绝对的)。

⼲扰程度受数据库或者操作事务的隔离级别来决定,隔离级别越⾼,⼲扰就越低,数据的⼀致性越好,并发性就越差。

持久性(Druability):⼀旦事务提交成功,数据就被持久化到数据库,不可以回滚。

2.spring使⽤注解对事务的控制 Spring 事务管理有两种⽅式:编程式事务管理、声明式事务管理 编程式事务管理通过TransactionTemplate⼿动管理事务,在实际应⽤中很少使⽤,我们来重点学习声明式事务管理 声明式事务管理有三种实现⽅式:基于TransactionProxyFactoryBean的⽅式、基于AspectJ的XML⽅式、基于注解的⽅式 1. 新建⼀个java⼯程——导⼊spring 和事务管理所需要的jar ——然后选择全部jar 右键Build path ——最后如图(我的java版本jre是1.8)2.在src⽬录下新建5个包如图 dao :数据连接层,主要⽤于存放对数据进⾏操作的类 model:模型层,主要⽤于存放实体类 service:服务层,主要⽤于对数据连接层进⾏操作的⼀些服务类。

util:⼯具类,主要⽤于存储⼯具⽅法 test:⽤于测试类3.在dao数据连接层,建⽴⾥与数据库操作的类与对应的接⼝(Order 订单,detail订单明细) 3.1 定义detailDao接⼝ 代码如下:1package com.spring.dao;23import com.spring.model.Detail;4import com.spring.model.Order;56public interface detailDao {7//保存订单明细8public void saveDetail(Detail detail);9101112 } 3.2 定义OrderDao接⼝代码如下:1package com.spring.dao;23import com.spring.model.Order;45public interface OrderDao {6//保存订单7public void saveOrder(Order order);891011 } 3.3 实现以上接⼝detailDaoImp 代码如下:1package com.spring.dao;23import javax.sql.DataSource;45import org.springframework.jdbc.core.JdbcTemplate;67import com.spring.model.Detail;8import com.spring.model.Order;910public class detailDaoImp implements detailDao {1112private DataSource dataSource;13private JdbcTemplate jdbcTemplate;1415public void setDataSource(DataSource dataSource) {16this.dataSource = dataSource;17this.jdbcTemplate = new JdbcTemplate(dataSource);18 }19//保存订单明细20public void saveDetail(Detail detail) {21 String SQL = "insert into t_detail values(null,?,?,?))";22 jdbcTemplate.update(SQL, new Object[] { detail.getItemName(),detail.getQuantity(),detail.getOrderId() });23 System.out.println("Insert detail success!");24 }2526 }OrderDaoImp代码如下:package com.spring.dao;import javax.sql.DataSource;import org.springframework.jdbc.core.JdbcTemplate;import com.spring.model.Order;public class OrderDaoImp implements OrderDao {private DataSource dataSource;private JdbcTemplate jdbcTemplate;public void setDataSource(DataSource dataSource) {this.dataSource = dataSource;this.jdbcTemplate = new JdbcTemplate(dataSource);}//插⼊订单public void saveOrder(Order order) {String SQL = "insert into t_order values (null,?)";System.out.println(SQL);System.out.println(order.getTotal_price());jdbcTemplate.update(SQL, new Object[]{order.getTotal_price()});System.out.println("Insert order success!");}}4.在model层中新建两个实体类 (Order订单类,detail订单明细类) Order订单类代码如下:1package com.spring.model;23/*4 * 订单表5*/6public class Order {7//订单编号8private Integer order_id;9//订单总⾦额10private Integer total_price;11public Integer getOrder_id() {12return order_id;13 }14public void setOrder_id(Integer order_id) {15this.order_id = order_id;16 }17public Integer getTotal_price() {18return total_price;19 }20public void setTotal_price(Integer total_price) {21this.total_price = total_price;22 }23 } detail订单明细类代码如下:1package com.spring.model;23/**4 * 商品明细表5 * @author Administrator6 *7*/8public class Detail {9//ID10private Integer detailId;11//外键 暂时可以忽略12private Integer orderId;13public Integer getDetailId() {14return detailId;15 }16public void setDetailId(Integer detailId) {17this.detailId = detailId;18 }19public Integer getOrderId() {20return orderId;21 }22public void setOrderId(Integer orderId) {23this.orderId = orderId;24 }25public Integer getQuantity() {26return quantity;27 }28public void setQuantity(Integer quantity) {29this.quantity = quantity;30 }31public String getItemName() {32return itemName;33 }34public void setItemName(String itemName) {35this.itemName = itemName;36 }37//商品数量38private Integer quantity;39//商品数量40private String itemName;4142 }5.在service中定义⼀个接⼝并且实现它 OrderService代码如下:1package com.spring.service;3import com.spring.model.Detail;4import com.spring.model.Order;56public interface OrderService {7//插⼊订单和订单明细8public void saveOrderAndDetail(Order order,Detail detail);9 } OrderServiceImp代码如下:1package com.spring.service;23import org.springframework.transaction.annotation.Transactional;45import com.spring.dao.OrderDaoImp;6import com.spring.dao.detailDaoImp;7import com.spring.model.Detail;8import com.spring.model.Order;910/**11 * 服务层使⽤注解来实现事务管理12 *13 * @author Administrator14 *15*/1617public class OrderServiceImp implements OrderService {18// 注⼊两个对象19public OrderDaoImp OrderDaoImp;2021public detailDaoImp detailDaoImp;2223 @Transactional24 @Override25// 如果加上@Transaction时,⽅法执⾏有异常,整个事务数据都会回滚,数据库中不会存在有数据。

spring的传播机制

spring的传播机制

spring的传播机制前⾔:Spring的事务,也就是数据库的事务操作,符合ACID标准,也具有标准的事务隔离级别。

但是Spring事务有⾃⼰的特点,也就是事务传播机制。

所谓事务传播机制,也就是在事务在多个⽅法的调⽤中是如何传递的,是重新创建事务还是使⽤⽗⽅法的事务?⽗⽅法的回滚对⼦⽅法的事务是否有影响?这些都是可以通过事务传播机制来决定的。

本⽂就测试⼀下这些事务传播机制的使⽤及异同1.准备测试⽅法主要是创建两个service接⼝(接⼝主要是对数据库表的操作),并创建其实现类1)创建beans.xml,开启事务<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:aop="/schema/aop"xmlns:tx="/schema/tx"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans.xsd/schema/tx/schema/tx/spring-tx.xsd/schema/aop/schema/aop/spring-aop.xsd"><tx:annotation-driven transaction-manager="transactionManager"/></beans>2)创建实体类和表(表创建读者可⾃定义创建)@Data@AllArgsConstructor@NoArgsConstructorpublic class Blog {private int id;private String name;private String ur;}3)创建service接⼝(BlogService和BlogService2,主要是对Blog的不同操作)// BlogServicepackage jdbc;// 主要负责Blog的添加和修改public interface BlogService {void save(Blog blog);void update(Blog blog);}// BlogService2package jdbc;// 主要负责Blog的删除public interface BlogService2 {void delete(int id);}4)创建其实现类(BlogServiceImpl,BlogService2)BlogServiceImpl.java@Transactional(propagation=Propagation.REQUIRED)@Componentpublic class BlogServiceImpl implements BlogService {@Autowiredprivate JdbcTemplate jdbcTemplate;@Autowiredprivate BlogService2 blogService2;@Overridepublic void save(Blog blog) {String sql = "insert into blog values(?,?,?)";jdbcTemplate.update(sql,new Object[]{blog.getId(),blog.getName(),blog.getUr()},new int[]{java.sql.Types.INTEGER,java.sql.Types.VARCHAR,java.sql.Types.VARCHAR});blogService2.delete(16);// update(blog);// throw new RuntimeException("error");}@Overridepublic void update(Blog blog){String sql = "update blog set name = ? where id=?";jdbcTemplate.update(sql, new Object[]{blog.getName(),blog.getId()},new int[]{java.sql.Types.VARCHAR,java.sql.Types.INTEGER});}}BlogService2.java@Transactional(propagation=Propagation.REQUIRED)@Componentpublic class BlogServiceImpl2 implements BlogService2 {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic void delete(int id){String sql = "delete from blog where id=?";jdbcTemplate.update(sql, id);}}注意:既然要实现多事务的传播,就需要在⼀个⽅法⾥调⽤另⼀个类的⽅法,下⾯的测试就是基于这种⽅法,在BlogService的save()⽅法中调⽤BlogService2的delete()⽅法5)创建Configuration类,⽤于创建DataSource实现@Configuration@ComponentScan(basePackages={"jdbc"})// 扫描BlogService实现类所在的包路径@ImportResource(locations={"classpath:beans.xml"})// 添加事务管理public class JdbcConfig {@Beanpublic JdbcTemplate jdbcTemplate(DataSource dataSource){return new JdbcTemplate(dataSource);}@Beanpublic DataSourceTransactionManager transactionManager(DataSource dataSource){return new DataSourceTransactionManager(dataSource);}@Beanpublic DataSource dataSource(){try {return new SimpleDriverDataSource(new com.mysql.jdbc.Driver(), "jdbc:mysql://localhost:3306/test", "root", "root");} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;}}6)测试public class Test {public static void main(String[] args) {AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(JdbcConfig.class);BlogService service = ac.getBean(BlogService.class);Blog b = new Blog(18,"lili","url");service.save(b);}}总结:⼤体的测试框架就如上所⽰,下⾯的测试修改主要是修改BlogServiceImpl和BlogServiceImpl2的事务传播机制@Transactional(propagation=Propagation.REQUIRED)3.事务传播机制的测试1)REQUIRED定义:如果有事务则加⼊事务,如果没有事务,则创建⼀个新的(默认值)操作1:将BlogServiceImpl和BlogServiceImpl2的事务传播机制都修改为@Transactional(propagation=Propagation.REQUIRED)结果1:操作2:将BlogServiceImpl事务传播机制修改为@Transactional(propagation=Propagation.NOT_SUPPORTED),BlogServiceImpl2的仍为@Transactional(propagation=Propagation.REQUIRED)结果2:总结:当BlogServiceImpl提供事务的时候,BlogServiceImpl2的⽅法执⾏使⽤当前已有事务,不再新建事务;当BlogServiceImpl不创建事务的时候,BlogServiceImpl2的⽅法执⾏发现没有事务可⽤,⾃⼰新建事务;2)NOT_SUPPORTED定义:Spring不为当前⽅法开启事务,相当于没有事务操作:将BlogServiceImpl和BlogServiceImpl2的事务传播机制都修改为@Transactional(propagation=Propagation.NOT_SUPPORTED)结果:总结:NOT_SUPPORTED相当于没有Spring事务,每条执⾏语句单独执⾏,单独提交3)REQUIRES_NEW定义:不管是否存在事务,都创建⼀个新的事务,原来的⽅法挂起,新的⽅法执⾏完毕后,继续执⾏⽼的事务操作:将BlogServiceImpl事务传播机制修改为@Transactional(propagation=Propagation.REQUIRED),BlogServiceImpl2的仍为@Transactional(propagation=Propagation.REQUIRES_NEW)结果:总结:REQUIRES_NEW为当前⽅法创建⼀个新的事务,并且当前事务先提交,然后再提交⽼的事务4)MANDATORY定义:必须在⼀个已有的事务中执⾏,否则报错操作:将BlogServiceImpl事务传播机制修改为@Transactional(propagation=Propagation.NOT_SUPPORTED),BlogServiceImpl2的仍为@Transactional(propagation=Propagation.MANDATORY),查看是否报错结果:总结:MANDATORY必须在已有事务下被调⽤,否则报错NOT_SUPPORTED执⾏数据库层⾯的事务操作,故当前测试中,insert⽅法成功执⾏,delete⽅法的抛错并不影响insert⽅法的执⾏5)NEVER定义:必须在⼀个没有的事务中执⾏,否则报错操作:将BlogServiceImpl事务传播机制修改为@Transactional(propagation=Propagation.REQUIRED),BlogServiceImpl2的仍为@Transactional(propagation=Propagation.MANDATORY),查看是否报错结果:总结:NEVER必须在没有事务的⽅法中执⾏,否则报错;save⽅法开启⼀个事务,还没来及提交发现delete⽅法报错,只能回滚事务6)SUPPORTS定义:如果其他bean调⽤这个⽅法时,其他bean声明了事务,则就⽤这个事务,如果没有声明事务,那就不⽤事务操作1:将BlogServiceImpl事务传播机制修改为@Transactional(propagation=Propagation.REQUIRED),BlogServiceImpl2的仍为@Transactional(propagation=Propagation.SUPPORTS)结果1:操作1:将BlogServiceImpl事务传播机制修改为@Transactional(propagation=Propagation.NOT_SUPPORTED),BlogServiceImpl2的仍为@Transactional(propagation=Propagation.SUPPORTS)结果1:总结:SUPPORTS类型的事务传播机制,是否使⽤事务取决于调⽤⽅法是否有事务,如果有则直接⽤,如果没有则不使⽤事务7)NESTED定义:如果当前存在事务,则在嵌套事务内执⾏。

Spring事务传播机制

Spring事务传播机制

Spring事务传播机制⼀、什么是事务传播机制事务传播机制是当⼀个事务⽅法被另⼀个事务⽅法调⽤时,这个事务⽅法应该如何去执⾏,例如method1⽅法添加了事务,去调⽤了method2事务⽅法,那么method2是继续在method1的事务中执⾏,还是新开⼀个事务时执⾏,这就需要method2的事务传播机制来决定。

在Spring中。

事务控制是基于AOP实现的,它给我们提供了⼀个注解@Transactional,所以在实际中我们只需要使⽤这个注解就⾏了。

⼆、为什么需要⼀个事务传播机制在Spring中。

我们不⽤去关⼼事务是什么时候开始、提交或者回滚的。

但是在这其中会出现⼀些问题,⽐如在两个service中:① service1的⽅法调⽤了service2的⽅法,这两个⽅法都有事务,这时如果service2的⽅法发⽣异常,是让service2提交还是两个⽅法⼀起回滚;② service1的⽅法调⽤了service2的⽅法,但是只有service1的⽅法加了事务,这时是否将service2也加⼊到service1的事务中去,如果service2的⽅法发⽣异常,是否需要回滚service1;③ service1的⽅法调⽤了service2的⽅法,这两个⽅法都有事务,service2的⽅法已经执⾏完毕,紧接着继续执⾏service1的后续代码,这时发⽣异常,是否需要回滚service2⽅法。

三、7种事务传播⾏为在开始介绍之前,我们⾸先要明确⼀点,Spring是使⽤的AOP代理的事务控制,它是针对于接⼝和类的,如果在同⼀个service类中的两个⽅法相互调⽤,传播机制并不会⽣效。

传播⾏为含义PROPAGATION_REQUIRED 这是默认的传播⾏为。

表⽰当前⽅法必须运⾏在事务中,如果当前事务存在,就直接使⽤这个事务,否则,开启⼀个新的事务。

简单地说就是,如果存在事务,就⽤该事务,否则就创建⼀个事务拿来⽤。

PROPAGATION_REQUIRED_NEW 表⽰当前⽅法必须运⾏在⾃⼰的事务中,会启动⼀个新的事务,如果存在当前事务,在执⾏期间就会挂起当前事务。

Spring中的事件传播机制

Spring中的事件传播机制

Spring中的事件传播机制2010-05-05 18:20在Spring中,事件传播机制与java中的观察者模式原理相同。

任何一个类要能够成为事件源,首先得继承自ApplicationContextAware等相关API,同时在相应的方法中产生事件对象,并通过ApplicationContext的publishEvent方法对事件进行传播,而监听器(实现了ApplicationListener接口)在对所传播的事件监听时做出相应的逻辑判断并采取相应的措施。

例子:事件类:ActionEvent监听类:ActionListener发布事件,通知监听的类:ActionLogicSpring配置文件:测试:test输出:详解:我们可以看到,我们运行logic.execute()方法时,自动调用了ActionListener的onApplicationEvent方法。

也许我们现在还觉得很奇怪,我们并没有调用ActionListener类啊,这是因为在ApplicationContext会自动在当前所有的Bean中寻找ApplicationListener接口的实现,并将其作为事件接收的对象。

当applicationContext.publishEvent(event)方法调用时,所有的ApplicationListener接口实现都会被激发,在每个ApplicationListener可以根据事件的类型判断是自己需要处理的事件。

这就是我们在ActionListener的onApplicationEvent方法中的如下处理:if(event instanceofActionEvent){PersonBean person = (PersonBean) event.getSource();System.out.println("Name:" + person.getName());System.out.println("Password:" + person.getPassword());}判断event是不是自己发布的事件,如果是,则进行相应的处理。

Spring事务传播行为详解

Spring事务传播行为详解

Spring事务传播⾏为详解转载⾃:前⾔Spring在TransactionDefinition接⼝中规定了7种类型的事务传播⾏为。

事务传播⾏为是Spring框架独有的事务增强特性,他不属于的事务实际提供⽅数据库⾏为。

这是Spring为我们提供的强⼤的⼯具箱,使⽤事务传播⾏可以为我们的开发⼯作提供许多便利。

但是⼈们对他的误解也颇多,你⼀定也听过“service⽅法事务最好不要嵌套”的传⾔。

要想正确的使⽤⼯具⾸先需要了解⼯具。

本⽂对七种事务传播⾏为做详细介绍,内容主要代码⽰例的⽅式呈现。

基础概念1. 什么是事务传播⾏为?事务传播⾏为⽤来描述由某⼀个事务传播⾏为修饰的⽅法被嵌套进另⼀个⽅法的时事务如何传播。

⽤伪代码说明:public void methodA(){methodB();//doSomething}@Transaction(Propagation=XXX)public void methodB(){//doSomething}代码中methodA()⽅法嵌套调⽤了methodB()⽅法,methodB()的事务传播⾏为由@Transaction(Propagation=XXX)设置决定。

这⾥需要注意的是methodA()并没有开启事务,某⼀个事务传播⾏为修饰的⽅法并不是必须要在开启事务的外围⽅法中调⽤。

2. Spring中七种事务传播⾏为事务传播⾏为类型说明PROPAGATION_REQUIRED如果当前没有事务,就新建⼀个事务,如果已经存在⼀个事务中,加⼊到这个事务中。

这是最常见的选择。

PROPAGATION_SUPPORTS⽀持当前事务,如果当前没有事务,就以⾮事务⽅式执⾏。

PROPAGATION_MANDATORY使⽤当前的事务,如果当前没有事务,就抛出异常。

PROPAGATION_REQUIRES_NEW新建事务,如果当前存在事务,把当前事务挂起。

PROPAGATION_NOT_SUPPORTED以⾮事务⽅式执⾏操作,如果当前存在事务,就把当前事务挂起。

这一次搞懂Spring事务是如何传播的

这一次搞懂Spring事务是如何传播的

这⼀次搞懂Spring事务是如何传播的前⾔上⼀篇分析了,本质上是将事务封装为切⾯加⼊到AOP的执⾏链中,因此会调⽤到MethodInceptor的实现类的invoke⽅法,⽽事务切⾯的Interceptor就是TransactionInterceptor,所以本篇直接从该类开始。

正⽂事务切⾯的调⽤过程public Object invoke(MethodInvocation invocation) throws Throwable {// Work out the target class: may be {@code null}.// The TransactionAttributeSource should be passed the target class// as well as the method, which may be from an interface.Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);// Adapt to TransactionAspectSupport's invokeWithinTransaction...return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);}这个⽅法本⾝没做什么事,主要是调⽤了⽗类的invokeWithinTransaction⽅法,注意最后⼀个参数,传⼊的是⼀个lambda表达式,⽽这个表达式中的调⽤的⽅法应该不陌⽣,在分析AOP调⽤链时,就是通过这个⽅法传递到下⼀个切⾯或是调⽤被代理实例的⽅法,忘记了的可以回去看看。

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,final InvocationCallback invocation) throws Throwable {// If the transaction attribute is null, the method is non-transactional.//获取事务属性类 AnnotationTransactionAttributeSourceTransactionAttributeSource tas = getTransactionAttributeSource();//获取⽅法上⾯有@Transactional注解的属性final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);//获取事务管理器final PlatformTransactionManager tm = determineTransactionManager(txAttr);final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);Object retVal = null;try {// 调⽤proceed⽅法retVal = invocation.proceedWithInvocation();}catch (Throwable ex) {// target invocation exception//事务回滚completeTransactionAfterThrowing(txInfo, ex);throw ex;}finally {cleanupTransactionInfo(txInfo);}//事务提交commitTransactionAfterReturning(txInfo);return retVal;}// 省略了else}这个⽅法逻辑很清晰,⼀⽬了然,if⾥⾯就是对声明式事务的处理,先调⽤createTransactionIfNecessary⽅法开启事务,然后通过invocation.proceedWithInvocation调⽤下⼀个切⾯,如果没有其它切⾯了,就是调⽤被代理类的⽅法,出现异常就回滚,否则提交事务,这就是Spring事务切⾯的执⾏过程。

Spring事务管理(详解+实例)

Spring事务管理(详解+实例)

1 初步理解理解事务之前,先讲一个你日常生活中最常干的事:取钱。

比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱;然后ATM出1000元钱。

这两个步骤必须是要么都执行要么都不执行。

如果银行卡扣除了1000块但是ATM出钱失败的话,你将会损失1000元;如果银行卡扣钱失败但是ATM却出了1000块,那么银行将损失1000元。

所以,如果一个步骤成功另一个步骤失败对双方都不是好事,如果不管哪一个步骤失败了以后,整个取钱过程都能回滚,也就是完全取消所有操作的话,这对双方都是极好的。

事务就是用来解决类似问题的。

事务是一系列的动作,它们综合在一起才是一个完整的工作单元,这些动作必须全部完成,如果有一个失败的话,那么事务就会回滚到最开始的状态,仿佛什么都没发生过一样。

在企业级应用程序开发中,事务管理必不可少的技术,用来确保数据的完整性和一致性。

事务有四个特性:ACID∙原子性(Atomicity):事务是一个原子操作,由一系列动作组成。

事务的原子性确保动作要么全部完成,要么完全不起作用。

∙一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。

在现实中的数据不应该被破坏。

∙隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。

∙持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。

通常情况下,事务的结果被写到持久化存储器中。

2 核心接口Spring事务管理的实现有许多细节,如果对整个接口框架有个大体了解会非常有利于我们理解事务,下面通过讲解Spring的事务接口来了解Spring实现事务的具体策略。

Spring事务管理涉及的接口的联系如下:2.1 事务管理器Spring并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
相关文档
最新文档