Spring事务管理原理及方法详解

这篇文章主要介绍了Spring事务管理原理及方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

事务,在日常开发或者面试中都必定会涉及到。开发工作中,结合数据库开发理解就是:一组dml要么全部成功执行提交,要么因为某一个操作异常,撤销之前所做的成功的操作,整体执行失败。再简单点的一句话:生死与共。

由此,可以看出,事务的必要性:在开发工作中,保证操作数据的安全性。事务的控制也就是保证数据的访问安全性。

一、事务的四大特性

A:原子性(atomicity),对数据的修改,要么全部成功执行,要么全部不执行。

C:一致性(consistency),一旦事务完成,系统必须保证数据职员是满足业务状态的一种一致状态中。很难懂的解释,跟原子性很像。一个事务在操作过程中,数据可能会产生很多中间态,一致性保证中间态对其他事务不可见,因为这些中间态,与事务的开始和结束的状态是不一致的。也就是从一种正确的状态到另一种正确的状态。

I:隔离性(isolation),事务之间的执行应不相互影响,也即事务执行的独立。

D:持久性(durability),事务一旦提交,则对数据库的修改是永久性的。

二、事务的隔离级别

并发环境下,事务可能会存在若干问题:脏读、幻读、不可重复读、第一类更新丢失、第二类更新丢失。

类型   说明 举例
脏读 A事务读取到了B事务未提交的数据  A开启事务=>B开启事务,读取账户1000块,取走100块=>A读取账户金额,读取到900=>B回滚事务。此时A读取的余额数据是无效的
幻读  一个事务里面的操作发现了未被操作的数据
A开启事务,修改某些数据状态=>B开启事务,执行新增数据并提交=>A事务提交,会出现一条未被修改的数据。

幻读发生的前提是并发事务中发生了新增或者删除动作。

不可重复读  一个事务中,先后两次读取数据,读到的结果不一致
A开启事务,读取账户1000块=>B开启事务,读取账户1000块,取出100块并提交事务=>A再读取账户余额,余额900块。

一个事务范围内的两次同样的查询,却返回了两次不同的数据,这就是不可重复读

第一类更新丢失 A事务撤销,把已经提交的B事务的更新的数据覆盖 A开启事务,读取账户1000块=>B开启事务,读取账户1000块,然后增加100块,提交事务,账户变为1100=>A撤销回滚事务,账户成1000块
第二类更新丢失 A事务提交,把已经提交的B事务的更新的数据覆盖 A开启事务,读取账户1000块=>B开启事务,读取账户1000块,然后增加100块,提交事务,账户变为1100=>A增加100块,提交事务,账户变为1100。

针对并发环境下可能出现的事务问题,于是就出现了隔离级别的解决方案,由低到高依次是:读未提交(Read uncommitted)、读已提交(Read committed)、可重复读(Repeatable read)、串行序列化(serializable)。下表展示出不同的隔离级别,对于脏读、幻读、不可重复读是否会出现。

类型 脏读 不可重复读 幻读 说明
Read uncommitted 会   
Read committed 不会  
Repeatable read 不会 不会 mysql的默认隔离级别
serializable 不会 不会 不会 最严格的隔离级别,将事务串行化执行,性能低。

mysql中查询当前隔离级别:select @@tx_isolation;

三、spring事务支持的隔离级别和传播特性

spring中定义了五种隔离界别和七种传播行为(可以在org.springframework.transaction.TransactionDefinition类中看到详细的解释)

1、spring支持的隔离级别

ISOLATION_DEFAULT:默认级别。一般是使用的是数据库本身的隔离级别(mysql - Repeatable read 、oracle - Read committed)

余下ISOLATION_READ_UNCOMMITTED、ISOLATION_READ_COMMITTED、ISOLATION_REPEATABLE_READ、ISOLATION_SERIALIZABLE分别对应上述数据库隔离级别配置。

2、传播特性

事务的传播特性就是在多个事务方法互相调用的时候,事务该如何在方法之间使用传播:

  •     PROPAGATION_REQUIRED:如果当前有事务,则加入该事务中。如果没有,则新建事务。
  •     PROPAGATION_SUPPORTS:如果当前有事务,则加入该事务中。如果没有,则以非事务状态运行。
  •     PROPAGATION_MANDATORY:如果当前有事务,则加入该事务中。如果没有,则抛出无事务异常
  •     PROPAGATION_REQUIRES_NEW:新建事务。如果当前存在事务,则挂起该事务。
  •     PROPAGATION_NOT_SUPPORTED:非事务状态运行。如果当前存在事务,则挂起该事务。
  •     PROPAGATION_NEVER:非事务状态运行。如果当前存在事务,则抛出异常。
  •     PROPAGATION_NESTED:如果当前有事务,则嵌套事务(父子事务)执行。如果没有,类似PROPAGATION_REQUIRED处理。

  spring默认的传播行为是PROPAGATION_REQUIRED,一般适用于绝大多数的开发工作。

3、事务的超时属性

事务在超过预定时间内还未完成操作,则自动回滚事务。TransactionDefinition 中以int值来表示超时时间,单位是秒,提供的默认值是TIMEOUT_DEFAULT = -1,即永不超时,一直等待操作完成

四、spring事务配置方法

spring并不具体直接的管理事务,而是提供了一个接口org.springframework.transaction.PlatformTransactionManager,该接口中主要定义了三个方法:getTransaction(获取事务)、commit(提交)和rollback(回滚)。

根据不同的持久化策略,spring提供了不同的实现,比如jdbc -

org.springframework.jdbc.datasource.DataSourceTransactionManager、hibernate - org.springframework.orm.hibernate5.HibernateTransactionManager等,在其他的实现可以通过源码去查询。

spring事务使用,可以分为编程式事务和声明式事务。编程式事务每次业务使用都得书写获取事务、设置事务隔离级别和传播特性、提交或回滚事务,代码的重复太高,费时费力,且如果代码的功能性复杂时候,使用编程式变得更加痛苦。而声明式的事务,属于无侵入式的,不会影响主业务流程,且编写上非常简单。所以目前开发工作中,更多的是使用声明式事务。

1、编程式事务

//to do。后续补充

2、声明式事务

声明式事务分为两种:基于aop的织入和@Transactional的注解。

2.1、基于aop的事务织入

之后在servcie中定义方法,最好的就是tx:method中定义的格式开头,就会执行特定的事务。

2.2、注解事务

注解事务第一部分的数据源和事务管理器配置同上,配置文件中需要修改的是开启注解配置:

然后在service编程中,加注解@Transactional即可(建议只在service实现类中加),如下是配置样例,其中的属性可以按需设置:

@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ,timeout = 100, readOnly = false, rollbackFor = {},noRollbackFor = {})

注意点:

事务的异常回滚只检查RuntimeException的异常,checked exception(如ClassNotFoundException、FileNotFoundException等)不会滚,捕获异常不抛出也不会回滚。

五、spring和springmvc父子容器

现在开发工作中,一般大多数都使用的spring和springmvc构建,这里,spring容器和springmvc容器就构成了父子容器的关系。父容器spring是发现不了子容器springmvc中的bean的,而子容器可以发现父容器中注册的bean。由此,实际开发工作中,不注意的话,往往会产生一些意想不到的问题。

首先,通常我们配置spring配置文件applicationContext.xml的时候,会配置如下的扫描:

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

这个配置会扫描指定包下面的所有@Component类型注解,包括@Controller,@Service,@Respository,并将扫描到的bean注册到spring容器中。

一般,spring配置文件中,还会出现下面的配置,作用是扫描@Required、@Autowired、 @PostConstruct、@PersistenceContext、@Resource、@PreDestroy等注解。理论上,此配置为可选配置,因为上面的扫描配置会默认打开。

<context:annotation-config/>

接下来配置springmvc的配置文件spring-mvc.xml,配置扫描注解@RequestMapping、@RequestBody、@ResponseBody等,同时,该配置默认加载很多参数绑定方法 。

<mvc:annotation-driven />

上面一句话,相当于:

<!--配置注解控制器映射器,它是SpringMVC中用来将Request请求URL到映射到具体Controller-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!--配置注解控制器映射器,它是SpringMVC中用来将具体请求映射到具体方法-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>

上面聊完基本配置,以下梳理下,来了解可能产生的容器冲突,对于事务管理的影响。

首先,有两个基本的容器:spring和springmvc,配置文件分别为applicationContext.xml和spring-mvc.xml

1、applicationContext.xml中配置<context:component-scan base-package="com.cfang" />,扫描指定包下的所有bean,并自动注册到spring容器中

2、spring-mvc.xml配置<mvc:annotation-driven />,扫描相关的springmvc的注解

3、为了保证springmvc的正常跳转,通常我们还得在spring-mvc.xml文件中配置包扫描<context:component-scan base-package="com.cfang" />。

按照以上配置信息,就会产生事务失效。原因就在于:

Spring容器优先加载由ServletContextListener(对应applicationContext.xml)产生的父容器,

而SpringMVC(对应spring-mvc.xml)产生的是子容器。子容器Controller进行扫描装配时装配的@Service注解的实例是没有经过事务加强处理,即没有事务处理能力的Service,

而父容器进行初始化的Service是保证事务的增强处理能力的。如果不在子容器中将Service排除(exclude)掉,此时得到的将是无事务处理能力的Service。

解决办法按照官方建议的来配置,各自负责一部分加载:

spring扫描:

<context:component-scan base-package="com.cfang.WeChat" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
  </context:component-scan>

springmvc扫描:

<context:component-scan base-package="com.cfang.WeChat" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
  </context:component-scan>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Spring中事务管理的四种方法(银行转账为例)

    前言 本文配套示例代码下载地址(完整可运行,含sql文件,下载后请修改数据库配置):点击这里下载 一.事务的作用 将若干的数据库操作作为一个整体控制,一起成功或一起失败. 原子性:指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生. 一致性:指事务前后数据的完整性必须保持一致. 隔离性:指多个用户并发访问数据库时,一个用户的事务不能被其他用户的事务所干扰,多个并发事务之间数据要相互隔离. 持久性:指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,即时数据库发生故障也不应

  • springboot中事务管理@Transactional的注意事项与使用场景

    前言:在service层的方法上使用@Transactional 即可实现处理数据库发生错误时触发事务回滚机制. 注意: Spring 基于注解的声明式事物 @Transactional 默认情况下只会对运行期异常(java.lang.RuntimeException及其子类)和 Error 进行回滚. 数据库引擎要支持事物,使用InnoDB. @Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没

  • MyBatis在Spring环境下的事务管理

    MyBatis的设计思想很简单,可以看做是对JDBC的一次封装,并提供强大的动态SQL映射功能.但是由于它本身也有一些缓存.事务管理等功能,所以实际使用中还是会碰到一些问题--另外,最近接触了JFinal,其思想和Hibernate类似,但要更简洁,和MyBatis的设计思想不同,但有一点相同:都是想通过简洁的设计最大限度地简化开发和提升性能--说到性能,前段时间碰到两个问题: 1.在一个上层方法(DAO方法的上层)内删除一条记录,然后再插入一条相同主键的记录时,会报主键冲突的错误. 2.某些项

  • Spring+SpringMVC配置事务管理无效原因及解决办法详解

    一般我们在Spring的配置文件application.xml中对Service层代码配置事务管理,可以对Service的方法进行AOP增强或事务处理如事务回滚,但是遇到一个问题,在Controller类中调用Service层方法,配置的事务管理会失效,查询相关资料发现原因.其实Spring和SpringMVC俩个容器为父子关系,Spring为父容器,而SpringMVC为子容器.也就是说application.xml中应该负责扫描除@Controller的注解如@Service,而Spring

  • 详解Springboot事务管理

    在Spring Boot事务管理中,实现自接口PlatformTransactionManager. public interface PlatformTransactionManager { org.springframework.transaction.TransactionStatus getTransaction(org.springframework.transaction.TransactionDefinition transactionDefinition) throws org.

  • SpringMVC+MyBatis 事务管理(实例)

    前言 spring事务管理包含两种情况,编程式事务.声明式事务.而声明式事务又包括基于注解@Transactional和tx+aop的方式.那么本文先分析编程式注解事务和基于注解的声明式事务. 编程式事务管理使用TransactionTemplate或者PlatformTransactionManager.对于编程式事务spring推荐使用TransactionTemplate. 一.编程式事务 spring事务特性 spring中所有的事务策略类都继承自org.springframework.

  • Spring事务管理方法步骤解析

    1.Spring的事务管理主要包括3个接口 TransactionDefinition:封装事务的隔离级别,超时时间,是否为只读事务和事务的传播规则等事务属性,可通过XML配置具体信息. PlatformTransactionManager:根据TransactionDefinition提供的事务属性配置信息,创建事务. TransactionStatus:封装了事务的具体运行状态.比如,是否是新开启事务,是否已经提交事务,设置当前事务为rollback-only等. 2.Spring的事务管理

  • 详解SpringBoot的事务管理

    Springboot内部提供的事务管理器是根据autoconfigure来进行决定的. 比如当使用jpa的时候,也就是pom中加入了spring-boot-starter-data-jpa这个starter之后. Springboot会构造一个JpaTransactionManager这个事务管理器. 而当我们使用spring-boot-starter-jdbc的时候,构造的事务管理器则是DataSourceTransactionManager. 这2个事务管理器都实现了spring中提供的Pl

  • Spring中的事务管理如何配置

    这篇文章主要介绍了spring中的事务管理如何配置,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在springboot中,使用事务非常的简单,因为springboot已经帮我们配置好了,只需要加上注解@Transactional即可 在spring中我们需要做一些配置:主要有三点: @Transactional:在相应的方法上加上这个注解 @EnableTransactionManagement:在配置类中加上,开启事务管理 需要在配置类中加

  • Spring事务管理原理及方法详解

    这篇文章主要介绍了Spring事务管理原理及方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 事务,在日常开发或者面试中都必定会涉及到.开发工作中,结合数据库开发理解就是:一组dml要么全部成功执行提交,要么因为某一个操作异常,撤销之前所做的成功的操作,整体执行失败.再简单点的一句话:生死与共. 由此,可以看出,事务的必要性:在开发工作中,保证操作数据的安全性.事务的控制也就是保证数据的访问安全性. 一.事务的四大特性 A:原子性(ato

  • Spring boot jpa 删除数据和事务管理的问题实例详解

    今天我们介绍的是jpa删除和事务的一些坑,接下来看看具体内容. 业务场景(这是一个在线考试系统)和代码:根据问题的id删除答案 repository层: int deleteByQuestionId(Integer questionId); service 层: public void deleteChoiceAnswerByQuestionId(Integer questionId) { choiceAnswerRepository.deleteByQuestionId(questionId)

  • RocketMQ事务消息原理与使用详解

    目录 一.RocketMQ事务消息概要 二.RocketMQ事务消息使用案例 (1).定义消息监听器 (2).定义消息生产者 (3).定义消息消费者 (4).观察生产者控制台输出 (5).观察消费者控制台输出 三.RocketMQ事务消息原理 四.RocketMQ事务消息使用限制 一.RocketMQ事务消息概要 RocketMQ事务消息(Transactional Message)是指应用本地事务和发送消息操作可以被定义到全局事务中,要么同时成功,要么同时失败.RocketMQ的事务消息提供类

  • Spring循环依赖的解决方法详解

    目录 什么是循环依赖: Spring实例Bean的本质 循环依赖主要场景 什么情况下循环依赖可以被解决 解决方式 说明:spring如何解决循环依赖,是面试中经常问到的题目,今天我们就来分享一下spring是如何解决循环依赖问题的. 什么是循环依赖: 我们先来看看官方文档的说法: 通俗来讲,就是A依赖B或者B依赖A,或者C依赖自己本身,或是三个以上,例如A依赖B,B依赖C,C又依赖A.如下图: Spring实例Bean的本质 Spring在实例化一个bean的时候,是首先递归的实例化其所依赖的所

  • Java事务管理学习之Hibernate详解

    环境与版本 hibernate 版本:Hibernate 4.2.2 (下载后的文件名为hibernate-release-4.2.2.Final.zip,解压目录hibernate-release-4.2.2.Final) 数据库: Oracle 10g 导入lib\required 中的所有jar 包 理论说明 1.SessionFactory负责创建Session,SessionFactory是线程安全的,多个并发线程可以同时访问一个SessionFactory 并从中获取Session实

  • Vue的状态管理vuex使用方法详解

    引入vuex 当访问数据对象时,一个 Vue 实例只是简单的代理访问.所以,如果有一处需要被多个实例间共享的状态,可以简单地通过维护一份数据来实现共享 const sourceOfTruth = {} const vmA = new Vue({ data: sourceOfTruth }) const vmB = new Vue({ data: sourceOfTruth }) 现在当 sourceOfTruth 发生变化,vmA 和 vmB 都将自动的更新引用它们的视图.子组件们的每个实例也会

  • Java Spring事务使用及验证过程详解

    事务,只要是为了保证数据的原子性.避免出现脏数据. 下面来讲解下spring是如何使用事务的. 1.配置事务.这里采用的是注解的模式 <!-- 配置事务管理器 ,如果你暂时未使用到事务可以不配置,次以下内容均可以在不适用事务的情况下删除 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"

  • Java弹簧布局管理器使用方法详解

    由 SpringLayout 类实现的布局管理器称为弹簧布局管理器.利用该布局管理器管理组件,当改变窗体的大小时,能够在不改变组件间相对位置的前提下自动调整组件大小,使组件依旧布满整个窗体,从而保证了窗体的整体效果.下面,通过一个实例来看看弹簧布局管理器的使用方法和效果. 弹簧布局管理器以容器和组件的边缘为操作对象,通过为组件和容器边缘以及组件和组件边缘建立约束,实现对组件布局的管理.通过方法 putConstraint(String e1,Conponet c1,int pad,String

  • Java事务管理学习之JDBC详解

    什么是Java事务 通常的观念认为,事务仅与数据库相关. 事务必须服从ISO/IEC所制定的ACID原则.ACID是原子性(atomicity).一致性(consistency).隔离性(isolation)和持久性(durability)的缩写.事务的原子性表示事务执行过程中的任何失败都将导致事务所做的任何修改失效.一致性表示当事务执行失败时,所有被该事务影响的数据都应该恢复到事务执行前的状态.隔离性表示在事务执行过程中对数据的修改,在事务提交之前对其他事务不可见.持久性表示已提交的数据在事务

  • Python实现TCP探测目标服务路由轨迹的原理与方法详解

    本文实例讲述了Python实现TCP探测目标服务路由轨迹的原理与方法.分享给大家供大家参考,具体如下: 一 点睛 在此次实践中,通过scapy的traceroute()方法实现探测机到目标服务器的路由轨迹,整个过程的原理见下图,首先通过探测机以SYN方式进行TCP服务扫描,同时启动tcpdump进行抓包,捕获扫描过程经过的所有路由点,再通过graph()方法进行路由IP轨迹绘制,中间调用ASN映射查询IP地理信息并生成svg流程文档,最后使用ImageMagick工 具将svg格式转换成png,

随机推荐