文章目录

  • @Transactional的实现
  • @Transactional的使用
  • Transaction的传播级别
    • REQUIRED
    • SUPPORTS
    • MANDATORY
    • NEVER
    • NOT_SUPPORTED
    • REQUIRES_NEW
    • NESTED
  • Transaction的隔离级别
    • READ_UNCOMMITTED
    • READ_COMMITTED
    • REPEATABLE_READ
    • SERIALIZABLE

Spring Boot JPA 中transaction的使用

transaction是我们在做数据库操作的时候不能回避的一个话题,通过transaction,我们可以保证数据库操作的原子性,一致性,隔离性和持久性。

本文我们将会深入的探讨Spring Boot JPA中@Transactional注解的使用。

通过@Transactional注解,我们可以设置事物的传播级别和隔离级别,同时可以设置timeout, read-only, 和 rollback等特性。

@Transactional的实现

Spring通过创建代理或者操纵字节码来实现事物的创建,提交和回滚操作。如果是代理模式的话,Spring会忽略掉@Transactional的内部方法调用。

如果我们有个方法callMethod,并标记它为@Transactional,那么Spring Boot的实现可能是如下方式:

createTransactionIfNecessary();
try {callMethod();commitTransactionAfterReturning();
} catch (exception) {completeTransactionAfterThrowing();throw exception;
}

@Transactional的使用

@Transactional使用起来很简单,可以放在class上,可以放在interface上,也可以放在方法上面。

如果放在方法上面,那么该方法中的所有public方法都会应用该Transaction。

如果@Transactional放在private方法上面,则Spring Boot将会忽略它。

Transaction的传播级别

传播级别Propagation定义了Transaction的边界,我们可以很方便的在@Transactional注解中定义不同的传播级别。

下面我们来分别看一下Transaction的传播级别。

REQUIRED

REQUIRED是默认的传播级别,下面的两种写法是等价的:

    @Transactionalpublic void deleteBookWithDefaultTransaction(Long id) {bookRepository.deleteBookById(id);}@Transactional(propagation = Propagation.REQUIRED)public void deleteBookWithRequired(Long id) {}

Spring会检测现在是否有一个有效的transaction。如果没有则创建,如果有transaction,则Spring将会把该放方法的业务逻辑附加到已有的transaction中。

我们再看下REQUIRED的伪代码:

if (isExistingTransaction()) {if (isValidateExistingTransaction()) {validateExisitingAndThrowExceptionIfNotValid();}return existing;
}
return createNewTransaction();

SUPPORTS

在SUPPORTS的情况下,Spring首先会去检测是否有存在Transaction,如果存在则使用,否则不会使用transaction。

我们看下代码怎么使用:

    @Transactional(propagation = Propagation.SUPPORTS)public void deleteBookWithSupports(Long id) {}

SUPPORTS的实现伪代码如下:

if (isExistingTransaction()) {if (isValidateExistingTransaction()) {validateExisitingAndThrowExceptionIfNotValid();}return existing;
}
return emptyTransaction;

MANDATORY

在MANDATORY情况下,Spring先会去检测是否有一个Transaction存在,如果存在则使用,否则抛出异常。

我们看下代码怎么使用:

    @Transactional(propagation = Propagation.MANDATORY)public void deleteBookWithMandatory(Long id) {}

MANDATORY的实现逻辑如下:

if (isExistingTransaction()) {if (isValidateExistingTransaction()) {validateExisitingAndThrowExceptionIfNotValid();}return existing;
}
throw IllegalTransactionStateException;

NEVER

如果是NEVER的情况下,如果现在有一个Transaction存在,则Spring会抛出异常。

使用的代码如下:

    @Transactional(propagation = Propagation.NEVER)public void deleteBookWithNever(Long id) {}

实现逻辑代码如下:

if (isExistingTransaction()) {throw IllegalTransactionStateException;
}
return emptyTransaction;

NOT_SUPPORTED

如果使用的是NOT_SUPPORTED,那么Spring将会首先暂停现有的transaction,然后在非transaction情况下执行业务逻辑。

我们这样使用:

    @Transactional(propagation = Propagation.NOT_SUPPORTED)public void deleteBookWithNotSupported(Long id) {}

REQUIRES_NEW

当REQUIRES_NEW使用时,Spring暂停当前的Transaction,并创建一个新的。

我们看下代码怎么使用:

    @Transactional(propagation = Propagation.REQUIRES_NEW)public void deleteBookWithRequiresNew(Long id){}

相应的实现代码如下:

if (isExistingTransaction()) {suspend(existing);try {return createNewTransaction();} catch (exception) {resumeAfterBeginException();throw exception;}
}
return createNewTransaction();

NESTED

NESTED顾名思义,是嵌套的Transaction,Spring首先检查transaction是否存在,如果存在则创建一个savepoint,如果我们的程序抛出异常的时候,transaction将会回滚到该savepoint。如果没有transaction,NESTED的表现和REQUIRED一样。

我们看下怎么使用:

    @Transactional(propagation = Propagation.NESTED)public void deleteBookWithNested(Long id){}

Transaction的隔离级别

隔离级别就是我们之前提到的原子性,一致性,隔离性和持久性。隔离级别描述了改动对其他并发者的可见程度。

隔离级别主要是为了防止下面3个并发过程中可能出现的问题:

  1. 脏读: 读取一个transaction还没有提交的change
  2. 不可重复读:在一个transaction修改数据库中的某行数据时,另外一个transaction多次读取同一行数据,获取到的不同的值。
  3. 幻读: 在一个transaction添加或者删除数据库的数据时,另外一个transaction做范围查询,获得了不同的数据行数。

READ_UNCOMMITTED

READ_UNCOMMITTED是隔离级别中最低的级别。这个级别下,并发的3个问题都可能出现。

我们这样使用:

    @Transactional(isolation = Isolation.READ_UNCOMMITTED)public void deleteBookWithReadUncommitted(Long id){}

READ_COMMITTED

READ_COMMITTED可以防止脏读。

我们看下代码:

    @Transactional(isolation = Isolation.READ_COMMITTED)public void deleteBookWithReadCommitted(Long id){}

REPEATABLE_READ

REPEATABLE_READ可以防止脏读和不可重复读。

使用的代码如下:

    @Transactional(isolation = Isolation.REPEATABLE_READ)public void deleteBookWithRepeatableRead(Long id){}

SERIALIZABLE

SERIALIZABLE是最严格的基本,可以防止脏读,不可重复读和幻读。

我们看下怎么使用:

    @Transactional(isolation = Isolation.SERIALIZABLE)public void deleteBookWithSerializable(Long id){}

本文的例子可以参考https://github.com/ddean2009/learn-springboot2/tree/master/springboot-transaction

更多精彩内容且看:

  • 区块链从入门到放弃系列教程-涵盖密码学,超级账本,以太坊,Libra,比特币等持续更新
  • Spring Boot 2.X系列教程:七天从无到有掌握Spring Boot-持续更新
  • Spring 5.X系列教程:满足你对Spring5的一切想象-持续更新
  • java程序员从小工到专家成神之路(2020版)-持续更新中,附详细文章教程

更多教程请参考 flydean的博客

Spring Boot JPA 中transaction的使用相关推荐

  1. Spring Boot JPA中java 8 的应用

    文章目录 Optional Stream API CompletableFuture Spring Boot JPA中java 8 的应用 上篇文章中我们讲到了如何在Spring Boot中使用JPA ...

  2. Spring Boot JPA中关联表的使用

    文章目录 添加依赖 构建Entity 构建Repository 构建初始数据 测试 Spring Boot JPA中关联表的使用 本文中,我们会将会通过一个Book和Category的关联关系,来讲解 ...

  3. Spring Boot JPA中使用@Entity和@Table

    文章目录 默认实现 使用@Table自定义表格名字 在JPQL Queries中重写表格名字 Spring Boot JPA中使用@Entity和@Table 本文中我们会讲解如何在Spring Bo ...

  4. Spring Boot JPA的查询语句

    文章目录 准备工作 Containing, Contains, IsContaining 和 Like StartsWith EndsWith 大小写不敏感 Not @Query Spring Boo ...

  5. Spring Boot JPA 2.7.2

    icon: edit date: 2022-01-02 category: CategoryA tag: tag A tag B star: true Spring Boot JPA 2.7.2 项目 ...

  6. Spring Boot Jpa 配置多个数据源,并读取其中一个表的具体数据

    总体简介: Spring Boot Jpa配置多个数据源(此次两个mysql数据库),访问其中一个库 alime_counsel_assign_log下的assign_data_backflow表,实 ...

  7. 在Spring Boot项目中使用Spock框架

    转载:https://www.jianshu.com/p/f1e354d382cd Spock框架是基于Groovy语言的测试框架,Groovy与Java具备良好的互操作性,因此可以在Spring B ...

  8. spring boot jpa级联保存

    spring boot jpa级联保存 CascadeType oneToMany关系 one的一方中加 @OneToMany(fetch = FetchType.EAGER, cascade = C ...

  9. 解决spring boot+JPA实现操作数据库时编辑时也变成了新增

    场景:使用spring boot+JPA框架开发项目的时候,新增数据是正常的,但是编辑有时候会变成新增,JPA判断是否新增对象有两个方法:1根据id,2根据版本号.我在开发项目中用的是根据版本号进行判 ...

最新文章

  1. 4.Spring Security 添加图形验证码
  2. jenkins构建一个maven项目[五]
  3. win7html文件,教你win7浏览器打不开本地html文件格式的解决方法
  4. 【自动驾驶】29.坐标变换与坐标轴旋转
  5. python模块批量安装方法_python离线批量安装依赖包
  6. tkinter拦截关闭事件
  7. java 获取oracle表结构_Java导出oracle表结构实例详解
  8. 从新手到高手 c++全方位学习_股票新手怎样快速入门?关于散户学习炒股的几点建议...
  9. 使用lua实现nginx rewrite
  10. java解析字符串方法_java字符串的截取方法substring()代码解析
  11. 双主动桥隔离双向DC-DC变换器(七)设计建议及未来趋势、总结
  12. 用火箭送快递?淘宝宣布联合蓝箭航天起启动“宝箭”计划...
  13. 基于python的证件照_利用python自动生成证件照
  14. python 小说 云_Python 爬虫之网络小说下载
  15. 这场大雨还没把我浇醒吗?
  16. 什么是5G CPE?
  17. 打乱魔方软件_一种智能魔方打乱装置的制作方法
  18. 杨辉三角 c语言 二维数组
  19. 极米movin01x和z6x的区别哪个好
  20. 《“胡”说IC——菜鸟工程师完美进阶》

热门文章

  1. 机器学习-回归之逻辑回归算法原理及实战
  2. 视频码率,帧率和分辨率的区别
  3. 内存管理:_CrtDumpMemoryLeaks和_CrtSetBreakAlloc
  4. Kafka设计解析(三) : Kafka High Availability (下)
  5. recv send 阻塞和非阻塞
  6. 不一样的图片加载方式
  7. RabbitMQ Network Partitions 服务日志对比
  8. Go 如何利用 Linux 内核的负载均衡能力?
  9. 深度解密Go语言之sync.pool
  10. Git/SQL/正则表达式练习平台