前述

​ 这段时间在工作中碰到一个事务相关的问题。先说下这个问题的场景,我们是一个商城项目,正在开发优惠券模块,现在有一个需求是需要批量领取优惠券,而且在领券时,其中一张领取失败不能影响其他符合要求的券的领取。由于之前在开发时,在领券这一块一直做的是单张领取,所以在做批量的时候很简单的做了个循环,然后封装成一个批量领券的方法中。伪代码如下:

@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class CouponService {
/**
* 单独领取某张券
* @param couponCode
* @return
*/
public Coupon get(String couponCode) {
log.info("查询是否存在这个券");
if ("001".equals(couponCode) || "002".equals(couponCode)) {
return Coupon.builder().code(couponCode).name("优惠券A").build();
}
// 自定义的异常类,专门指定不符合规则的券被领取时抛出的状态
throw new CustomeException("不存在这个优惠券");
} /**
* 批量领取
* @param codes
* @return
*/
public List<Coupon> batchGet(List<String> codes) {
List<Coupon> target = new ArrayList<>();
codes.forEach(code -> {
Coupon coupon = null;
try {
coupon = get(code);
} catch (CustomeException e) {
log.error(e.getMessage());
}
target.add(coupon);
});
return target;
}
}

上面的方法在执行时会抛出异常

Transaction rolled back because it has been marked as rollback-only

我们来分析下这个异常:

首先我们要知道,spring中事务的默认传播机制是

PROPAGATION_REQUIRED:如果存在一个事务,则支持当前事务。如果没有事务则开启

​ 在这种传播机制下,batchGet方法跟循环中的get方法会共享一个事务,而在get方法抛出异常时,这个事务已经被标记为rollback-only了,在这种情况下,batchGet方法捕获了这个异常并没有继续向上抛出,所以会执行commit操作,而对一个被标记成rollback-only的方法执行commit操作,就会抛出以上错误。

​ 我的解决办法就是,在batcGet方法上将事务的隔离级别设置为PROPAGATION_SUPPORTS:如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行

好了,这个异常我们分析完了,现在我们进入我们这篇文章需要学的主题内容,主要是事务的传播机制及隔离级别。预期两篇文章,一篇理想学习,一篇源码分析,源码分析将以SpringBoot为主。希望能跟大家一起进步,学习,每天进步一点点就好~~~

Spring中事务的传播机制:

  1. ROPAGATION_REQUIRED:如果存在一个事务,则支持当前事务。如果没有事务则开启

解释:当A.methodA()和B.methodB()都打上REQUIRED的事务标志,执行A.methodA()方法的时候,看到上下文没有事务,会新建一个事务,当执行到b.methodB()的时候,发现上下文已经有事务了,则不会新建事务,用A.methodA()新建的那个事务。如果b.methodB()执行成功,a.methodA()执行失败,那么b.methodB()和a.methodA()都会回滚(用的都是a.methodA()的事务)

  1. PROPAGATION_SUPPORTS:如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行

解释:当B.methodB()打上PROPAGATION_SUPPORTS的事务标志,执行A.methodA()方法,当执行到b.methodB()的时候,会检查上下文有没有事务,如果A.methodA()有事务,则b.methodB()沿用该事务,反之b.methodB()就以非事物的方式执行

3. PROPAGATION_MANDATORY:如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常

解释:当B.methodB()打上PROPAGATION_MANDATORY的事务标志,执行A.methodA()方法,当执行到b.methodB()的时候,会检查上下文有没有事务,如果A.methodA()有事务,则b.methodB()沿用该事务,如果没有,则会抛出异常

4.PROPAGATION_REQUIRES_NEW:总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起

解释:当B.methodB()打上PROPAGATION_REQUIRES_NEW的事务标志,执行A.methodA()方法,当执行到b.methodB()的时候,会检查上下文有没有事务,如果A.methodA()有事务,则会挂起A.methodA()的事务,新建一个属于b.methodB(),当b.methodB()的事务执行结束的时候,则会唤醒b.methodB()的事务。和PROPAGATION_REQUIRED的差别在于回滚,当b.methodB()的事务提交后,A.methodA()执行失败,只会回滚A.methodA不会回滚b.methodB(),当b.methodB()执行失败,异常被A.methodA()方法catch到的话,A.methodA()事务不会回滚

  1. PROPAGATION_NOT_SUPPORTED:总是非事务地执行,并挂起任何存在的事务

解释:当B.methodB()打上PROPAGATION_NOT_SUPPORTED的事务标志,执行A.methodA()方法,当执行到b.methodB()的时候,会检查上下文有没有事务,如果A.methodA()有事务,则会挂起A.methodA()的事务,当执行完b.methodB()方法的时候,A.methodA()方法继续以事务的方式执行

  1. PROPAGATION_NEVER: 总是非事务地执行,如果存在一个活动事务,则抛出异常

解释:当B.methodB()打上PROPAGATION_NEVER的事务标志,执行A.methodA()方法,当执行到b.methodB()的时候,会检查上下文有没有事务,如果有事务,则抛出异常,如果没有则以非事务执行

  1. PROPAGATION_NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, PROPAGATION_REQUIRED 属性执行

解释:当B.methodB()打上PROPAGATION_NOT_SUPPORTED的事务标志,执行A.methodA()方法,当执行到b.methodB()的时候,如果A.methodA()方法有事务,则会用当前事务,如果 b.methodB()执行失败,只会回滚 b.methodB(),不会回滚A.methodA(),只有当A.methodA()执行完成后才会提交b.methodB()的事务,如果A.methodA()方法没有事务,就会新建一个事务;

Spring中事物的隔离级别

事务隔离级别:

ISOLATION_DEFAULT,

ISOLATION_READ_UNCOMMITTED,

ISOLATION_READ_COMMITTED,

ISOLATION_REPEATABLE_READ,

ISOLATION_GENERALIZABLE

1.ISOLATION_DEFAULT:这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别

2. ISOLATION_READ_UNCOMMITTED :这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。

3. ISOLATION_READ_COMMITTED :保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。:

4. ISOLATION_REPEATABLE_READ :这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。

5. ISOLATION_SERIALIZABLE :这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻读。

spring学习笔记(九)事务学习(上)的更多相关文章

  1. 学习笔记:CentOS7学习之十九:Linux网络管理技术

    目录 学习笔记:CentOS7学习之十九:Linux网络管理技术 本文用于记录学习体会.心得,兼做笔记使用,方便以后复习总结.内容基本完全参考学神教育教材,图片大多取材自学神教育资料,在此非常感谢MK ...

  2. 软件测试之loadrunner学习笔记-01事务

    loadrunner学习笔记-01事务<转载至网络> 事务又称为Transaction,事务是一个点为了衡量某个action的性能,需要在开始和结束位置插入一个范围,定义这样一个事务. 作 ...

  3. WCF学习笔记之事务编程

    WCF学习笔记之事务编程 一:WCF事务设置 事务提供一种机制将一个活动涉及的所有操作纳入到一个不可分割的执行单元: WCF通过System.ServiceModel.TransactionFlowA ...

  4. 多线程学习笔记九之ThreadLocal

    目录 多线程学习笔记九之ThreadLocal 简介 类结构 源码分析 ThreadLocalMap set(T value) get() remove() 为什么ThreadLocalMap的键是W ...

  5. MDX导航结构层次:《Microsoft SQL Server 2008 MDX Step by Step》学习笔记九

    <Microsoft SQL Server 2008 MDX Step by Step>学习笔记九:导航结构层次   SQL Server 2008中SQL应用系列及BI笔记系列--目录索 ...

  6. go微服务框架kratos学习笔记九(kratos 全链路追踪 zipkin)

    目录 go微服务框架kratos学习笔记九(kratos 全链路追踪 zipkin) zipkin使用demo 数据持久化 go微服务框架kratos学习笔记九(kratos 全链路追踪 zipkin ...

  7. c++学习笔记之封装篇(上)

    title: c++学习笔记之封装篇(上) date: 2017-03-12 18:59:01 tags: [c++,c,封装,类] categories: [学习,程序员,c/c++] --- 一. ...

  8. python3.4学习笔记(九) Python GUI桌面应用开发工具选择

    python3.4学习笔记(九) Python GUI桌面应用开发工具选择 Python GUI开发工具选择 - WEB开发者http://www.admin10000.com/document/96 ...

  9. Go语言学习笔记九: 指针

    Go语言学习笔记九: 指针 指针的概念是当时学C语言时了解的.Go语言的指针感觉与C语言的没啥不同. 指针定义与使用 指针变量是保存内存地址的变量.其他变量保存的是数值,而指针变量保存的是内存地址.这 ...

  10. Spark学习笔记2——RDD(上)

    目录 Spark学习笔记2--RDD(上) RDD是什么? 例子 创建 RDD 并行化方式 读取外部数据集方式 RDD 操作 转化操作 行动操作 惰性求值 Spark学习笔记2--RDD(上) 笔记摘 ...

随机推荐

  1. 动手学Transformer

    动手实现Transformer,所有代码基于tensorflow2.0,配合illustrated-transformer更香. 模型架构 Encoder+Decoder Encoder Decode ...

  2. AJ学IOS(06)UI之iOS热门游戏_超级猜图

    AJ分享,必须精品 先看效果图 思路 需求分析 1,搭建界面 1>上半部分,固定的,用Storyboard直接连线(OK) 2>下半部分,根据题目的变化,不断变化和调整,用代码方式实现比较 ...

  3. 【Server】Windows系统安装Tomcat服务器

    安装Tomcat服务器 Tomcat服务器地址:https://tomcat.apache.org/download-80.cgi 当前版本点选8以上版本,最新的可能不稳定,所以选8或者9版本 直接解 ...

  4. 用Taro做个微信小程序Todo, 小白工作记录

    微信小程序框架: Taro 做微信小程序的框架, 几个比较主流的: 官方的WePY: https://tencent.github.io/wepy/document.html#/ 美团的mpvue: ...

  5. Linux命令与Shell

    Linux 目录结构及解释 查看命令行执行完位置:  echo $BASH 命令记录 mkdir mkdir命令 用来创建目录. 语法:mkdir (选项)(参数) 主要选项: -m<目标属性& ...

  6. 移动端Vue组件库-Vant学习

    全局引入 import Vant from 'vant'; //嫌麻烦就全部一次导出,虽然包会稍微有点大 import 'vant/lib/index.css'; //注意导入全局的这个css,否则布 ...

  7. jmeter 聚合报告参数解释

    label:每个请求的名称 样本:发送给服务器的请求数量 平均值:平均响应时间,默认情况下是单个 Request 的平均响应时间,当使用了 Transaction Controller 时,也可以以T ...

  8. 最新VMware虚拟机安装Linux系统-CentOS(详细教程)

    一.前言 最近有网友反应初学Linx不会安装,找了许多教程不是太全面,总会遇到一些要不是启动不了,要不是连不上网,各种问题,为了让大家能够顺利的安装,小乐写了一个非常详细的教程,让大家少入坑. 二.背 ...

  9. MVC-基础02

    MVC是Model(模型).View(视图)和Controller(控制). 1)最上面的一层,是直接面向最终用户的"视图层"(View).它是提供给用户的操作界面,是程序的外壳. ...

  10. python 进阶篇 python 的值传递

    值传递和引用传递 值传递,通常就是拷贝参数的值,然后传递给函数里的新变量,这样,原变量和新变量之间互相独立,互不影响. 引用传递,通常是指把参数的引用传给新的变量,这样,原变量和新变量就会指向同一块内 ...