Spring虽然提供了灵活方便的事务管理功能,但是这些功能都是基于底层数据库本身的事务处理机制工作的,要深入了解Spring的事务管理和配置,有必要对数据库事务的基础知识进行学习!

数据库事务(简称:事务)

是数据库管理系统(DBMS)执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。

并非任意的对数据库的操作序列都是数据库事务。数据库事务拥有以下四个特性,习惯上被称之为ACID特性
原子性(Atomic):表示组成一个事务的多个数据库操作是一个不可分割的原子单元,只有所有的操作执行成功,整个事务才能提交,事务中任何一个数据操作失败,已经执行的任何操作都必须撤销,让数据库返回到初始状态。。
一致性(Consistency):事务操作成功后,数据库所处的状态和他的业务规则是一致的,即数据不会被破坏。如从A账户转账100元到B账户,不管操作成功与否,A和B的存款总额是不变的。
隔离性(Isolation):多个事务操作并发执行时,不同的事务拥有各自的数据空间,一个事务的执行不应影响其他事务的执行。准确的说并非要求做到完全无干扰,数据库规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性越好,但并发性越弱。
持久性(Durability):一旦事务提交成功后,事务中所有的数据操作都必须被持久化到数据库中,即使提交事务后,数据库马上崩溃,在数据库重启时,也必须能保证能够通过某种机制恢复数据。

在这些事务特性中,数据“一致性”是最终目标,其他的特性都是为达到这个目标的措施、要求或手段。

数据库管理系统一般采用重执行日志保证原子性、一致性和持久性,重执行日志记录了数据库变化的每一个动作,数据库在一个事务中执行一部分操作后发 生错误退出,数据库即可以根据重执行日志撤销已经执行的操作。此外,对于已经提交的事务,即使数据库崩溃,在重启数据库时也能够根据日志对尚未持久化的数 据进行相应的重执行操作。

和Java程序采用对象锁机制进行线程同步类似,数据库管理系统采用数据库锁机制保证事务的隔离性。当多个事务试图对相同的数据进行操作时,只有持有锁的事务才能操作数据,直到前一个事务完成后,后面的事务才有机会对数据进行操作。Oracle数据库还使用了数据版本的机制,在回滚段为数据的每个 变化都保存一个版本,使数据的更改不影响数据的读取。

数据库系统的四种事务隔离级别

尽管数据库为用户提供了锁的DML操作方式,但直接使用锁管理是非常麻烦的,因此数据库为用户提供了自动锁机制。只要用户指定会话的事务隔离级 别,数据库就会分析事务中的SQL语句,然后自动为事务操作的数据资源添加上适合的锁。此外数据库还会维护这些锁,当一个资源上的锁数目太多时,自动进行 锁升级以提高系统的运行性能,而这一过程对用户来说完全是透明的。

Read Commited:读已提交数据(会出现不可重复读和幻读)

Read Uncommited:读未提交数据(会出现脏读,不可重复读和幻读)。

Repeatable Read:可重复读(会出现幻读)

Serializable:串行化

SQL 92推荐使用REPEATABLE READ(MySQL默认隔离级别)以保证数据的读一致性,不过用户可以根据应用的需要选择适合的隔离等级。

数据并发的问题 

一个数据库可能拥有多个访问客户端,这些客户端都可以并发方式访问数据库。数据库中的相同数据可能同时被多个事务访问,如果没有采取必要的隔离措 施,就会导致各种并发问题,破坏数据的完整性。这些问题可以归结为5类,包括3类数据读问题(脏读、不可重复读和幻象读)以及2类数据更新问题(第一类丢 失更新和第二类丢失更新)。下面,我们分别通过实例讲解引发问题的场景。 

脏读

A事务读取B事务尚未提交的更改数据,并在这个数据的基础上操作。如果恰巧B事务回滚,那么A事务读到的数据就是无效的。

在Oracle数据库中,不会发生脏读的情况。

不可重复读:

在同一事务中,多次读取同一数据返回的结果有所不同。换句话说就是,后续读取可以读到另一事务已提交的更新数据。相反,“可重复读”在同一事务中多次读取数据时,能够保证所读数据一样,也就是,后续读取不能读到另一事务已提交的更新数据。

幻读:

A事务读取B事务提交的新增数据,这时A事务将出现幻象读的问题。象读一般发生在计算统计数据的事务中。

幻象读和不可重复读是两个容易混淆的概念,前者是指读到了其他事务已经提交的新增数据,而后者是指读到了其他事务已经提交的更改数据(更改或删除), 为了避免这两种情况,采取的对策是不同的,防止读取到更改数据,只需要对操作的数据添加行级锁,阻止操作中的数据发生变化,而防止读取到新增数据,则往往 需要添加表级锁——将整个表锁定,防止新增数据(Oracle使用多版本数据的方式实现)。

数据库锁机制 

数据并发会引发很多问题,在一些场合下有些问题是允许的,但在另外一些场合下可能却是致命的。数据库通过锁的机制解决并发访问的问题,虽然不同的数据库在实现细节上存在差别,但原理基本上是一样的。

按锁定的对象的不同,一般可以分为表锁定和行锁定,前者对整个表进行锁定,而后者对表中特定行进行锁定。从并发事务锁定的关系上看,可以分为共享 锁定和独占锁定。共享锁定会防止独占锁定,但允许其他的共享锁定。而独占锁定既防止其他的独占锁定,也防止其他的共享锁定。为了更改数据,数据库必须在进 行更改的行上施加行独占锁定,INSERT、UPDATE、DELETE和SELECT FOR UPDATE语句都会隐式采用必要的行锁定。下面我们介绍一下Oracle数据库常用的5种锁定。

  • 行共享锁定:一般通过SELECT FOR UPDATE语句隐式获得行共享锁定,在Oracle中用户也可以通过LOCK TABLE IN ROW SHARE MODE语句显式获得行共享锁定。行共享锁定并不防止对数据行进行更改的操作,但是可以防止其他会话获取独占性数据表锁定。允许进行多个并发的行共享和行 独占性锁定,还允许进行数据表的共享或者采用共享行独占锁定。
  • 行独占锁定:通过一条INSERT、UPDATE或DELETE语句隐式获取,或者通过一条LOCK TABLE IN ROW EXCLUSIVE MODE语句显式获取。这个锁定可以防止其他会话获取一个共享锁定、共享行独占锁定或独占锁定。
  • 表共享锁定:通过LOCK TABLE IN SHARE MODE语句显式获得。这种锁定可以防止其他会话获取行独占锁定(INSERT、UPDATE或DELETE),或者防止其他表共享行独占锁定或表独占锁 定,它允许在表中拥有多个行共享和表共享锁定。该锁定可以让会话具有对表事务级一致性访问,因为其他会话在用户提交或者回溯该事务并释放对该表的锁定之前 不能更改这个被锁定的表。
  • 表共享行独占:通过LOCK TABLE IN SHARE ROW EXCLUSIVE MODE语句显式获得。这种锁定可以防止其他会话获取一个表共享、行独占或者表独占锁定,它允许其他行共享锁定。这种锁定类似于表共享锁定,只是一次只能 对一个表放置一个表共享行独占锁定。如果A会话拥有该锁定,则B会话可以执行SELECT FOR UPDATE操作,但如果B会话试图更新选择的行,则需要等待。
  • 表独占:通过LOCK TABLE IN EXCLUSIVE MODE显式获得。这个锁定防止其他会话对该表的任何其他锁定。

不同的隔离级别采用不同的锁类型来实现,在四种隔离级别中,Serializable的隔离级别最高,Read Uncommited的隔离级别最低。

  • 大多数据库默认的隔离级别为Read Commited,如SqlServer
  • 当然也有少部分数据库默认的隔离级别为Repeatable_Read ,如Mysql,
  • Oracle数据库支持READ COMMITTED和SERIALIZABLE两种事务隔离性级别,不支持READ UNCOMMITTED和REPEATABLE READ这两种隔离性级别。虽然SQL标准定义的默认事务隔离性级别是SERIALIZABLE,但是Oracle数据库默认使用的事务隔离性级别却是READ COMMITTED.

Spring对事务管理的支持

Spring提供了两种事务管理方式:

编程式事务管理:

编写程序式的事务管理可以清楚的定义事务的边界,可以实现细粒度的事务控制,比如你可以通过程序代码来控制你的事务何时开始,何时结束等,与后面介绍的声明式事务管理相比,它可以实现细粒度的事务控制。

声明式事务管理:

如果你并不需要细粒度的事务控制,你可以使用声明式事务,在Spring中,你只需要在Spring配置文件中做一些配置,即可将操作纳入到事务管理中,解除了和代码的耦合, 这是对应用代码影响最小的选择。当你不需要事务管理的时候,可以直接从Spring配置文件中移除该设置

如果使用Spring, 我们就不再需要手工控制事务

事务传播规则(传播行为)

传播行为:定义关于客户端和被调用方法的事物边界

传播行为

意义

REQUIRED

(默认值)

业务方法需要在一个事务中运行。如果方法运行时,已经处在一个事务中,那么加入到该事务,否则为自己创建一个新的事务

NOT_SUPPORTED

声明方法不需要事务。如果方法没有关联到一个事务,容器不会为它开启事务。如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行

REQUIRESNEW

属性表明不管是否存在事务,业务方法总会为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务会被挂起,新的事务会被创建,直到方法执行结束,新事务才算结束,原先的事务才会恢复执行

MANDATORY

该属性指定业务方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果业务方法在没有事务的环境下调用,容器就会抛出例外。

SUPPORTS

这一事务属性表明,如果业务方法在某个事务范围内被调用,则方法成为该事务的一部分。如果业务方法在事务范围外被调用,则方法在没有事务的环境下执行

Never

指定业务方法绝对不能在事务范围内执行。如果业务方法在某个事务中执行,容器会抛出例外,只有业务方法没有关联到任何事务,才能正常执行

NESTED

如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按REQUIRED属性执行.它使用了一个单独的事务, 这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效

事务管理器

spring没有直接管理事务,而是将管理事务的责任委托给JTA或相应的持久性机制所提供的某个特定平台的事物实现

事务管理器实现 目标
org.springframework.jdbc.datasource.DataSourceTransactionManager 在单一的JDBC Datasource中的管理事务
org.springframework.orm.hibernate3.HibernateTransactionManager 当持久化机制是hibernate时,用它来管理事务
org.springframework.jdo.JdoTransactionManager 当持久化机制是Jdo时,用它来管理事务。
org.springframework.transaction.jta.JtaTransactionManager 使用一个JTA实现来管理事务。在一个事务跨越多个资源时必须使用
org.springframework.orm.ojb.PersistenceBrokerTransactionManager 当apache的ojb用作持久化机制时,用它来管理事务。

 声明式事务管理——基于XML配置

在spring配置文件中引入tx命名空间

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

<!-- 加载外部的配置文件 -->
<context:property-placeholder location="classpath:cn/itcast/spring/p_jdbc/jdbc.properties"/><!-- 一、配置数据库连接池 ComboPooledDataSource -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><!-- 基本的连接信息 --><property name="jdbcUrl" value="${jdbcUrl}"></property><property name="driverClass" value="${driverClass}"></property><property name="user" value="${username}"></property><property name="password" value="${password}"></property><!-- 一些管理的配置 --><!--初始化时获取三个连接,取值应在minPoolSize与maxPoolSize之间。Default: 3 --><property name="initialPoolSize" value="3"></property><!--连接池中保留的最小连接数。Default: 3 --><property name="minPoolSize" value="3"></property><!--连接池中保留的最大连接数。Default: 15 --><property name="maxPoolSize" value="5"></property><!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 --><property name="acquireIncrement" value="3"></property><!--最大空闲时间,1800秒内未使用则连接被丢弃,若为0则永不丢弃。Default: 0 --><property name="maxIdleTime" value="1800"></property>
</bean>
<!-- 三、配置声明式事务管理(告诉它哪些方法需要事务) -->
<!-- 1,配置事务管理器(应根据情况使用合适的事务管理器) -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property>
</bean><!-- 2,配置管理事务的“通知” -->
<tx:advice id="txAdvice" transaction-manager="transactionManager"><!-- 配置哪些方法要使用什么样的事务配置,没有匹配到的方法不会为其管理事务 --><tx:attributes><!-- 指定所有以add,delete,update开头的方法都使用事务,
默认read-only="false" --><tx:method name="add*" /><tx:method name="delete*" /><tx:method name="update*" /><!-- 指定所有以query开头的方法都是使用只读的事务 --><tx:method name="query*" read-only="true" /></tx:attributes>
</tx:advice><!-- 3,配置切面 -->
<aop:config><!-- 指定拦截所有Dao中的方法 --><aop:advisor advice-ref="txAdvice" pointcut="execution(* *..*Dao*.*(..))" />
</aop:config>

声明式事务管理——基于注解配置

在spring中要做的配置

<!-- 加载外部的配置文件 -->
<context:property-placeholder location="classpath:cn/itcast/spring/p_jdbc/jdbc.properties"/><!-- 一、配置数据库连接池 ComboPooledDataSource -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><!-- 基本的连接信息 --><property name="jdbcUrl" value="${jdbcUrl}"></property><property name="driverClass" value="${driverClass}"></property><property name="user" value="${username}"></property><property name="password" value="${password}"></property><!-- 一些管理的配置 --><!--初始化时获取三个连接,取值应在minPoolSize与maxPoolSize之间。Default: 3 --><property name="initialPoolSize" value="3"></property><!--连接池中保留的最小连接数。Default: 3 --><property name="minPoolSize" value="3"></property><!--连接池中保留的最大连接数。Default: 15 --><property name="maxPoolSize" value="5"></property><!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 --><property name="acquireIncrement" value="3"></property><!--最大空闲时间,1800秒内未使用则连接被丢弃,若为0则永不丢弃。Default: 0 --><property name="maxIdleTime" value="1800"></property>
</bean>

<!-- 三、配置声明式事务管理(告诉它哪些方法需要事务) -->
<!-- 1,配置事务管理器(应根据情况使用合适的事务管理器) -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property>
</bean>
<!-- ==== 基于注解的方式配置事务 ==== -->
<tx:annotation-driven transaction-manager="transactionManager"/>

在类上或方法上写注解声明要使用事务

@Transactional(readOnly = true)
public class UserDao {
@Transactional(readOnly = false)public void save(final User user) {        //....}}

@Transactional注解说明

方法的事务设置将被优先执行。例如: UserServiceImpl类在类的级别上被注解为只读事务,但是,这个类中的 addUser(User uesr) 方法的@Transactional注解的事务设置将优先于类级别注解的事务设置。

@Transactional注解可以被继承,即:在父类上声明了这个注解,则子类中的所有public方法也都是会开事务的。

转载于:https://www.cnblogs.com/winner-0715/p/5427682.html

@Spring事务管理相关推荐

  1. Spring事务管理 与 SpringAOP

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

  2. 什么是事务的传播_这么漂亮的Spring事务管理详解,你不来看看?

    事务概念回顾 什么是事务? 事务是逻辑上的一组操作,要么都执行,要么都不执行. 事物的特性(ACID): 原子性: 事务是最小的执行单位,不允许分割.事务的原子性确保动作要么全部完成,要么完全不起作用 ...

  3. SPRING 事务管理说明

    spring 事务管理是通过AOP拦截指定的方法,进行事务管理. 事务配置 <aop:config proxy-target-class="true"><aop: ...

  4. Spring 事务管理高级应用难点剖析

    Spring 事务管理高级应用难点剖析: 第 1 部分 http://www.ibm.com/developerworks/cn/java/j-lo-spring-ts1/index.html htt ...

  5. spring事务管理 TransactionProxyFactoryBean源码分析

    J2EE,当然离不开事务,事务又当然少不了Spring声明式事务.spring声明式事务,很多码农门,应该和笔者一样,停留在使用上,及仅仅了解点原理.如:Spring事务管理原理"代理+AO ...

  6. Spring 事务管理高级应用难点剖析--转

    第 1 部分 http://www.ibm.com/search/csass/search/?q=%E4%BA%8B%E5%8A%A1&sn=dw&lang=zh&cc=CN& ...

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

    写这篇博客之前我首先读了<Spring in action>,之后在网上看了一些关于Spring事务管理的文章,感觉都没有讲全,这里就将书上的和网上关于事务的知识总结一下,参考的文章如下: ...

  8. 在Spring事务管理下,Synchronized为啥还线程不安全?

    在synchronized 锁住方法的情况下,竟然出现了脏写 Tips 昨天本来打算是准备着一支烟 一杯咖啡 一个bug写一天的,突然我们组长跟我们说线上环境报错了, 还出现了"服务器异常, ...

  9. 多数据源 事务管理_可能是最漂亮的Spring事务管理详解

    事务概念回顾 什么是事务? 事务是逻辑上的一组操作,要么都执行,要么都不执行. 事物的特性(ACID): 原子性: 事务是最小的执行单位,不允许分割.事务的原子性确保动作要么全部完成,要么完全不起作用 ...

  10. springaop事务逻辑原理_架构师:一篇文章掌握——Spring 事务管理

    对大多数Java开发者来说,Spring事务管理是Spring应用中最常用的功能,使用也比较简单.本文主要逐步介绍Spring事务管理的相关知识点及原理,作为Spring事务管理的学习总结. 一.关键 ...

最新文章

  1. $_server[#039;php_auth_user#039;],找不到’./mysql/user.MYD#039;(错误代码:13 – 权限被拒绝)...
  2. 更新了朋友圈微博动态,好友何时会点赞评论?
  3. Python---将一字符串转换为字典,并按词语出现的频率由高到低进行排列。
  4. python rpc框架-python使用rpc框架gRPC的方法
  5. python如何安装panda数据库_在Pycharm中安装Pandas库方法(简单易懂)
  6. 掌握jQuery插件开发
  7. 牛客练习赛46T1-华华教奕奕写几何【数学】
  8. mysql多大_洞悉MySQL底层架构:游走在缓冲与磁盘之间
  9. 南京大学2021计算机考研复试线是多少,34所自划线院校2021考研复试分数线-2021南京大学考研分数线已公布...
  10. LeetCode 881. 救生艇(贪心,双指针)
  11. tasm报错illegal memory reference的解决办法
  12. 读书笔记 - 深入解析Windows操作系统 - C1. 概念和工具
  13. 汉字一级字库与二级字库
  14. 对select标签中的option默认选中后端的数据
  15. scrapy爬虫框架实现简单案例:爬取阳光平台内容
  16. 联想笔记本重装windows10系统
  17. Windows10 CMD SSH登陆不了服务器出现 WARNING: REMOTE HOST
  18. Android调整Bitmap图片大小
  19. ResNet网络详解
  20. Java HashMap中在resize()时候的rehash,即再哈希法的理解

热门文章

  1. java三角形边长_利用java解决三角形角度问题
  2. E课网AHB-SRAMC
  3. apache的ab压力测试介绍
  4. 智能门锁:人脸识别技术
  5. kcl方程独立性的图论证明
  6. HtmlUnit基础
  7. JFS与JFS2的区别
  8. h5 bootstrap 小程序模板_汉中餐饮行业支付宝小程序模板
  9. 07-PDI(Kettle)源码编译8.2.0.0.R版本
  10. Android WebService(基于SOAP协议)个人记录总结