事务

事务的特性(ACID)

原子性(Atomicity):

标识将事务中所有的操作进行捆绑层一个不可分割的单元格,
计对事务所有进行的数据库修改等操作,要么全部执行,要么就是全部失败
隔离性(Isolation):
指的是一个事务的执行,不能被其他的事务进行干扰,一个事务内部的操作以及使用的数据库对并发的其他事务都是进行隔离的,并发执行的各个事务之间是不能进行相互干扰的  事务之间隔离,互不干扰
持久性(Durability):
永久性,指一个事务提交之后,它对数据库中数据的改变应该是永久性的

一致性(Consistency):
事务前后,数据库数据完整性不被破坏,总是与预期一致的状态,就像借钱,一方借多少,另一方加多少,数据不会凭空增多,也不会凭空减少。

数据是一致且持久的,操作是原子且隔离的

事务的四种隔离级别

①read uncommitted(读未提交):事物的修改,即使没有提交,对其他事务也是可见的。事务读未提交的数据成为脏读。
②read committed(读已提交):只能读取到其他事务已经提交的数据。
③repeatable read(可重复读):该级别解决了脏读、不可重复读的问题,保证了在一个事物中多次读到的数据是一致的,但是没有解决幻读的问题。(默认)
④serializable(串行化):事务挨个执行,避免了幻读的问题。

数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大,因为事务隔离实质上就是使事务在一定程度上 “串行化”进行,这显然与“并发”是矛盾的

同时,不同的应用对读一致性和事务隔离程度的要求也是不同的,比如许多应用对“不可重复读”和“幻读”并不敏感,可能更关心数据并发访问的能力。

主流数据库默认的事务隔离级别

Mysql——repeatable read(可重复读)

Oracle——read committed(读已提交)

PostGreSql——read committed(读已提交)

事务并发可能产生的问题(不考虑隔离级别)

脏读

读到另一事务还未提交的数据。

(只有读未提交隔离级别才会出现这种问题 。 eg:A对数据减10但还未提交,B读取到的数据数据已经少了10)

不可重复度

一个事务多次对相同的数据读取可能会出现不同的结果

(读未提交和读已提交的隔离级别下都可能会出现不可重复读的问题,关键在于重复读取的数据同时在被其他事务进行修改操作)

幻读/虚读:

当前事务读取数据时,读范围内的数据,被其他事务穿插有修改操作,导致出现读取幻象。

(在读未提交、读已提交和可重复读三种事务隔离级别下都可能会出现)

Spring事务

Spring管理事务的方式

  • 编程式事务,在代码中硬编码。(不推荐使⽤)
  • 声明式事务,在配置⽂件中配置(推荐使⽤)
    •   基于XML的声明式事务
    •   基于注解的声明式事务

Spring事务五种隔离级别

一种控制并发执行的事务对数据操作的规则。

TransactionDefinition 接⼝中定义了五个表示隔离级别的常量

TransactionDefinition.ISOLATION_DEFAULT:  数据库默认

使⽤后端数据库默认的隔离级别,Mysql 默认采⽤的 REPEATABLE_READ隔离级别 Oracle 默认采⽤的 READ_COMMITTED隔离级别.

TransactionDefinition.ISOLATION_READ_UNCOMMITTED:  读未提交

最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读

TransactionDefinition.ISOLATION_READ_COMMITTED:  读已提交

允许读取并发事务已经提交的数据,可以阻⽌脏读,但是幻读或不可重复读仍有可能发⽣

TransactionDefinition.ISOLATION_REPEATABLE_READ: 可重复读

对同⼀字段的多次读取结果都是⼀致的,除⾮数据是被本身事务⾃⼰所修改,可以阻⽌脏读和不可重复读,但幻读仍有可能发⽣。

TransactionDefinition.ISOLATION_SERIALIZABLE: 序列化

最⾼的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执⾏,这样事务之间就完全不可能产⽣⼲扰,也就是说,该

级别可以防⽌脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会⽤到该级别。

                                              --参考java Guide文章

Spring事务的7种传播行为

⽀持当前事务的情况:
TransactionDefinition.PROPAGATION_REQUIRED: 存在则加入,没有就新建

如果当前存在事务,则加⼊该事务;如果当前没有事务,则创建⼀个新的事务。

TransactionDefinition.PROPAGATION_SUPPORTS:存在则加入,没有则不管

如果当前存在事务,则加⼊该事务;如果当前没有事务,则以⾮事务的⽅式继续运⾏。

TransactionDefinition.PROPAGATION_MANDATORY: 存在则加入,没有就抛异常

如果当前存在事务,则加⼊该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)

不⽀持当前事务的情况:
TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建新事物,存在则挂起

创建⼀个新的事务,如果当前存在事务,则把当前事务挂起。

TransactionDefinition.PROPAGATION_NOT_SUPPORTED:非事务运行,存在则挂起

以⾮事务⽅式运⾏,如果当前存在事务,则把当前事务挂起。

TransactionDefinition.PROPAGATION_NEVER:非事务运行,存在则抛异常

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

其他情况:
TransactionDefinition.PROPAGATION_NESTED:存在则嵌套事务,没有就新建

如果当前存在事务,则创建⼀个事务作为当前事务的嵌套事务来运⾏;如果当前没有事务,则该取值等价TransactionDefinition.PROPAGATION_REQUIRED。

                                            --参考java Guide文章

Spring事务回滚rollbackFor

@Transactional(rollbackFor = Exception.class)

当 @Transactional 注解作⽤于类上时,该类的所有 public ⽅法将都具有该类型的事务属性,同时,我们也可以在⽅法级别使⽤该标注来覆盖类级别的定义。

一般用于方法级别。

如果类或者⽅法加了这个注解,那么这个类⾥⾯的⽅法抛出异常,就会回滚,数据库⾥⾯的数据也会回滚。

在 @Transactional 注解中如果不配置 rollbackFor 属性,那么事物只会在遇到 RuntimeException时候才会回滚,加上 rollbackFor=Exception.class ,可以让事物在遇到⾮运⾏时异常时也回滚。

场景验证

参考: https://blog.csdn.net/u014532775/article/details/106690766

Propagation.REQUIRED

在外围方法未开启事务的情况下Propagation.REQUIRED修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。
在外围方法开启事务的情况下Propagation.REQUIRED修饰的内部方法会加入到外围方法的事务中,所有Propagation.REQUIRED修饰的内部方法和外围方法均属于同一事务,只要一个方法回滚,整个事务均回滚。
特别:对于下面这种捕获异常的,事务注解的方法已经抛出异常了,只是在方法外进行了捕获并不影响事务回滚 =》三个事务都会回滚
 @Transactional
@Override
public void transaction_required_required_exception_try(){
User1 user1=new User1();
user1.setName("张三");
user1Service.addRequired(user1); User2 user2=new User2();
user2.setName("李四");
try {
user2Service.addRequiredException(user2);
} catch (Exception e) {
System.out.println("方法回滚");
}
} @Service
public class User1ServiceImpl implements User1Service {
//省略其他...
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void addRequired(User1 user){
user1Mapper.insert(user);
}
} @Service
public class User2ServiceImpl implements User2Service {
//省略其他...
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void addRequired(User2 user){
user2Mapper.insert(user);
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void addRequiredException(User2 user){
user2Mapper.insert(user);
throw new RuntimeException();
}
}

PROPAGATION_REQUIRES_NEW

在外围方法未开启事务的情况下Propagation.REQUIRES_NEW修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰

在外围方法开启事务的情况下Propagation.REQUIRES_NEW修饰的内部方法依然会单独开启独立事务,且与外部方法事务也独立,内部方法之间、内部方法和外部方法事务均相互独立,互不干扰。

Propagation.REQUIRES_NEW修饰方法抛出的异常在外部方法中如不捕获,会影响外部方法事务的回滚。

Spring事务方法套方法,内部事务方法不生效?

Spring事务用到代理,代理去对标记有@Transactional的方法开启事务startTransaction(),内部的调用是由被代理对象直接调用,不会再开启事务,因此内部事务不生效

解决办法,通常是将方法分别放在不同的service中

事务与spring事务的更多相关文章

  1. 数据库事务和spring事务的区别

    数据库事务和spring事务 本质上其实是同一个概念,spring的事务是对数据库的事务的封装,最后本质的实现还是在数据库,假如数据库不支持事务的话,spring的事务是没有作用的.数据库的事务说简单 ...

  2. 数据库程序接口——JDBC——功能第四篇——事务之Spring事务

    综述 事务的实现方式有三种,JTA,Spring事务,Web Container方式.本篇讲述Spring事务. Spring事务分为两个部分核心对象,Spring事务的实现方式. Spring事务实 ...

  3. hibernate的事务和spring事务的区别 (转)

    spring事务: 对于传统的基于特定事务资源的事务处理而言(如基于JDBC的数据库访问),Spring并不会对其产生什么影响,我们照样可以成功编写并运行这样的代码.同时,Spring还提供了一些辅助 ...

  4. MySQL事务及Spring事务管理

    事务,是在数据库中用于保证数据正确性的一种机制,涉及到很多概念以及不同的情况,这里做一个总结 相关概念 事务四特性(ACID) 原子性(Atomicity,或称不可分割性):要么全部完成或者全部不完成 ...

  5. 【声明式事务】Spring事务特性(二)

    spring所有的事务管理策略类都继承自org.springframework.transaction.PlatformTransactionManager接口. 其中TransactionDefin ...

  6. 【声明式事务】Spring事务介绍(一)

    事务管理对于企业应用来说是至关重要的,当出现异常情况时,它也可以保证数据的一致性. Spring事务有两种管理方式:编程式事务和声明式事务 编程式事务使用TransactionTemplate或者直接 ...

  7. 【Spring】Spring的事务管理 - 1、Spring事务管理概述(数据库事务、Spring事务管理的核心接口)

    Spring事务管理概述 文章目录 Spring事务管理概述 数据库事务 什么是Spring的事务管理? Spring对事务管理的支持 Spring事务管理的核心接口 Platform Transac ...

  8. spring事务传播机制实例讲解

    http://kingj.iteye.com/blog/1680350   spring事务传播机制实例讲解 博客分类:   spring java历险     天温习spring的事务处理机制,总结 ...

  9. 深入理解 Spring 事务原理

    本文由码农网 – 吴极心原创,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划! 一.事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供 ...

  10. spring 事务 笔记3.1

    Spring事务 以前的事务都是编程式事务,需要开启和关闭,然后程序写在这里面 spring,声明式事务 Spring事务隔离级别 DEFAULT 使用数据库默认隔离级别 READ_UNCOMMITT ...

随机推荐

  1. CentOS7加入AD域(winbind)

    作者:独笔孤行 官网:​​ ​http://anyamaze.com​​ 公众号:云实战 前言 AD域(Active Directory)是Windows服务器的活动目录,在目录中可以收录公司的电脑账 ...

  2. 原创如何给MDK5.37添加Arm Compiler 5

    最新发布的MDK5.37已经不再安装Arm Compiler 5(ARMCC)编译器了,因为点击魔术棒后,在Target选项卡中选择编译器时,会看到missing:compiler version 5 ...

  3. flask + gunicorn + nginx

    详解见网址:https://www.jianshu.com/p/dba83a473f12,问题解决:https://blog.51cto.com/yanconggod/1983494 我的配置:htt ...

  4. 自定义StringByteLength

    using HKElectric.ESafety.Utilities; using System.ComponentModel.DataAnnotations; namespace HKElectri ...

  5. 性能提升 40 倍!我们用 Rust 重写了自己的项目

    前言 Rust 已经悄然成为了最受欢迎的编程语言之一.作为一门新兴底层系统语言,Rust 拥有着内存安全性机制.接近于 C/C++ 语言的性能优势.出色的开发者社区和体验出色的文档.工具链和IDE 等 ...

  6. StreamReader和StreamWriter

    FileStream 是操作字节的 StreamReader跟StreamWriter是操作字符串的 操作文件的方法的命名空间都是IO using System; using System.Colle ...

  7. WPF 布局控件

    <!--Horizontal水平竖直排放元素默认Vertical竖直排放 加属性Orientation--> <StackPanel Orientation="Horizo ...

  8. FastAPI中声明参数为必需的三种方式

    前提 有时候我们定义一些参数的时候,需要声明这个参数为必需,请求者必须传递该参数.FatstAPI中声明参数为必需的方式有三种,分别为:不设默认值.  "..." 和 " ...

  9. golang流程控制if,switch分支

    if 分支 if 单分支 if 条件表达式 { 逻辑代码 } package main import "fmt" func main() { //var a int = 9 //i ...

  10. VS2010 发布网站总是连同cs文件一起发布了

    选择第一个,保存再发布.cs文件 都删除了.