Spring(13)_事务控制

我的梦境 提交于 2020-01-31 03:00:20

本系列博客汇总在这里:Spring 汇总


源码工程文件为:spring3.2_10 & spring3.2_11 & spring3.2_12 & spring3.2_13

一、什么是事务

一荣俱荣,一损俱损,很多复杂的操作我们可以把它看成是一个整体,要么同时成功,要么同时失败。

事务的四个特征ACID

  • 原子性(Atomic):表示组成一个事务的多个数据库的操作的不可分割的单元,只有所有的操作成功才算成功,整个事务提交,其中任何一个操作失败了都是导致整个所有操作失败,事务会回滚。
  • 一致性(Consistentcy):事务操作成功后,数据库所处的状态和业务规则一致。如果A账户给B账户汇 100,A 账户减去 100,B 加上 100,两个账户的总额是不变的。
  • 隔离性(islation):在多个数据库的操作相同的数据并发时,不同的事务有自己的数据空间,事务与事务之间不受干扰(不是绝对的)。干扰程度受数据库或者操作事务的隔离级别来决定,隔离级别越高,干扰就越低,数据的一致性越好,并发性就越差。
  • 持久性(Druability):一旦事务提交成功,数据就被持久化到数据库,不可以回滚。

二、Spring 使用注解对事务的控制

1、来处理事务传播特性

第一步

配置事务管理器

<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-3.2.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.2.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
           http://www.springframework.org/schema/tx
           http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
	<!-- Spring读取属性文件配置 -->
	<context:property-placeholder location="classpath:jdbc.properties"/>
	<!-- 数据源配置 -->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="${driverClassName}"></property>
		<property name="url" value="${url}"></property>
		<property name="username" value="${uname}"></property>
		<property name="password" value="${pword}"></property>
		<!-- 初始化的连接数 -->
		<property name="initialSize" value="${initialSize}"></property>
		<!-- 连接池的最大连接数-->
		<property name="maxActive" value="${maxActive}"></property>
		<!-- 最大的空闲的连接数 -->
		<property name="maxIdle" value="${maxIdle}"></property>
		<!-- 最小的空闲连接数 -->
		<property name="minIdle" value="${minIdle}"></property>
	</bean>
	
	<bean id="userDao" class="com.wyx.spring.dao.impl.OrderDaoImpl">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<bean id="detailDao" class="com.wyx.spring.dao.impl.DetailDaoImpl">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<bean id="userService" class="com.wyx.spring.service.impl.OrderServiceImpl">
		<property name="userDao" ref="userDao"></property>
	</bean>
	
	<!-- 定义事务的管理器 -->
	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 事务管理器的主键驱动 -->
	<tx:annotation-driven transaction-manager="txManager"/>
</beans>

第二步

通过 @Transactional 来标注要使用事务的类或接口或方法,在项目中我们通常都会把事务开启在Service 层,建议把注解标注在接口的实现类或者是方法上。

  • 注意:在 Service 层开启事务的时候,默认情况下,发生运行时异常会回滚,非运行时异常不会回滚。

可以设置对指定的异常回滚

  • rollbackFor 或 rollbackForClassName 设置对哪些回滚。
  • noRollbackFor 或 noRollbackForClassName 设置对哪些不回滚。
  • @Transactional 的默认传播特性是 reqired,实际项目中 80% 都是采用 reqired。
    在这里插入图片描述

事务的传播特性

  • REQUIRED:默认的传播特性,业务方法需要在一个事务中运行,如果一个方法已经处在一个事务中那么就加入到这个事务中,否则就会创建一个事务。
    在这里插入图片描述
    在这里插入图片描述

  • NEVER:指定的业务方法绝对不能在事务范围内运行,如果业务方法在某个事务中执行,就会抛异常,只有业务方法没有任何事务才正常执行。

    被嵌套的事务
    在这里插入图片描述
    在事务中运行
    在这里插入图片描述
    在这里插入图片描述

  • MANDATORY:该属性指定业务方法只能在一个已经存在的事务中执行,业务方法不能自己发起自己的事务,如果业务方法不存在事务,容器就抛异常。

    MANDATORY 完全和 NEVER 相反

    如果没有在事务中运行
    在这里插入图片描述
    在有事务的环境中
    在这里插入图片描述

  • SUPPORTS:如果业务方法中已经在某个事务中被调用,则方法就称为事务的一部分,如果外部业务方法没有开启事务,supports 该方法也会在没有事务的环境中执行。

    在没有事务的环境下运行
    在这里插入图片描述
    在有事务的环境下运行
    在这里插入图片描述

  • NOT_SUPPORTED:如果该业务方法在一个事务中被调用,那么当前的事务会被挂起,执行该业务方法,方法执行完毕唤醒被挂起的事务,如果业务方法不在一个事务中执行,该方法也不会开事务。不管是否在有无事务的环境中执行都不开启事务。

    不在事务中运行
    在这里插入图片描述
    在事务中运行
    在这里插入图片描述

  • REQUIRES_NEW:不管是否存在事务,业务方法总会自己开启一个事务,如果在已有事务的环境中调用,已有事务会被挂起,新的事务会被创建,直到业务方法调用结束,已有事务才被唤醒。

    不在事务中调用
    在这里插入图片描述
    在事务中调用
    在这里插入图片描述
    注意:内外事务不受影响

  • NESTED:如果业务方法在一个事务中执行,就在这个事务中嵌套,如果没有事务按着 required 执行,开启单独的事务,这种事务有多个事务的保存点,内部事务的回滚对外部事务没有影响。
    在这里插入图片描述
    在没有事务中执行
    在这里插入图片描述
    在已有事务中执行
    在这里插入图片描述
    在已有事务总 Nested 事务发生异常
    在这里插入图片描述
    Nested 事务正常,已有事务异常
    在这里插入图片描述

2、事务的并发

在这里插入图片描述

并发问题

脏读(dirty read)

A 事务读到 B 事务没有提交的数据,并且 A 来修改这个数据,如果恰巧 B 做事务回滚,那么 A 事务读到的数据就是错误的
在这里插入图片描述

不可重复读(unrepeatable read)

指的是 A 事务读取了 B 事务已经提交了的更改数据,假设 A 取款的过程中 B 向账户汇入 100,A 事务两次读取数据不一致。
在这里插入图片描述

幻读(phantom read)

A 事务读取 B 事务新增的数据,假设银行做在一个 A 事务中统计,在统计过程中 B 新增了用户,A 的事务中两次统计不同
在这里插入图片描述

第一类更新丢失

在这里插入图片描述

第二类更新丢失

在这里插入图片描述

3、事务的隔离级别

Sql92 标准提供 4 个隔离级别,会给我们自动根据不同事务的隔离级别加不同的锁
在这里插入图片描述
数据库的隔离级别越高,并发性就越差,性能就越低。

三、使用配置文件对事务控制

如有错误,欢迎指正!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!