Spring Boot JPA 中transaction的使用
文章目录
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是默认的传播级别,下面的两种写法是等价的:
@Transactional
public 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个并发过程中可能出现的问题:
- 脏读: 读取一个transaction还没有提交的change
- 不可重复读:在一个transaction修改数据库中的某行数据时,另外一个transaction多次读取同一行数据,获取到的不同的值。
- 幻读: 在一个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
更多教程请参考 flydean的博客
Spring Boot JPA 中transaction的使用的更多相关文章
- Spring Boot JPA中java 8 的应用
文章目录 Optional Stream API CompletableFuture Spring Boot JPA中java 8 的应用 上篇文章中我们讲到了如何在Spring Boot中使用JPA ...
- spring boot JPA中实体类常用注解
spring boot jpa中的注解很多,参数也比较多.没必要全部记住,但是经常查看官方文档也比较麻烦,记录一下一些常用的注解.通过一些具体的例子来帮助记忆. @Entity @Table(name ...
- Spring Boot JPA中关联表的使用
文章目录 添加依赖 构建Entity 构建Repository 构建初始数据 测试 Spring Boot JPA中关联表的使用 本文中,我们会将会通过一个Book和Category的关联关系,来讲解 ...
- Spring Boot JPA中使用@Entity和@Table
文章目录 默认实现 使用@Table自定义表格名字 在JPQL Queries中重写表格名字 Spring Boot JPA中使用@Entity和@Table 本文中我们会讲解如何在Spring Bo ...
- spring boot jpa 使用update 报错解决办法
在spring boot jpa 中自定义sql,执行update操作报错解决办法: 在@Query(...)上添加 @Modifying@Transactional注解
- Spring Boot JPA的查询语句
文章目录 准备工作 Containing, Contains, IsContaining 和 Like StartsWith EndsWith 大小写不敏感 Not @Query Spring Boo ...
- Spring Boot JPA 连接数据库
本文将介绍怎样在Spring Boot project中加入JPA作为持久化方式. 改动 pom.xml 依赖 与上一篇介绍的 jdbc 不同的是 spring-boot-starter-jdbc 改 ...
- Spring boot Jpa添加对象字段使用数据库默认值
Spring boot Jpa添加对象字段使用数据库默认值 jpa做持久层框架,项目中数据库字段有默认值和非空约束,这样在保存对象是必须保存一个完整的对象,但在开发中我们往往只是先保存部分特殊的字段其 ...
- Spring Boot(五):Spring Boot Jpa 的使用
在上篇文章Spring Boot(二):Web 综合开发中简单介绍了一下 Spring Boot Jpa 的基础性使用,这篇文章将更加全面的介绍 Spring Boot Jpa 常见用法以及注意事项. ...
随机推荐
- Javascript-什么是递归?
递归? 程序调用自身的编程技巧就称之为递归(recursion),就是再运行的过程中调用自己,本质上就是循环. 构成递归的条件有: Ⅰ.不能无限制的调用本身,必须有一个出口,化为简单的状况处理(非递归 ...
- 深入解读ES6系列(四)
来自老曾es6的前言: 哈喽小伙伴们,爱说'废'话的Z又回来了,欢迎来到Super IT曾的博客时间,上一节说了字符串,面向对象以及json的知识,这一节我们继续我们知识的海洋,一起奋斗不秃头!不足的 ...
- gitlab问题
1.gitclone前http://10.10.11.4:9999/SZRDC/I`````````.git改为http://git.berchina.com:9999/~~~~``` 2.Cloni ...
- 整数回文数判断 Python
判断一个整数是否是回文数.回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数. 输入:123 输出:false 输入:-121 输出:false 输入:121 输出:true 输入:1 ...
- PHP常用设计模式,PHP常用设计模式详解,PHP详解设计模式,PHP设计模式
PHP常用设计模式详解 单例模式: php交流群:159789818 特性:单例类只能有一个实例 类内__construct构造函数私有化,防止new实例 类内__clone私有化,防止复制对象 设置 ...
- Java工程中如何读取配置文件中参数信息
Java中读取配置文件中参数: 方法一:通过JDK中Properties来实现对配置文件的读取. Properties主要用于读取Java的配置文件,不同的编程语言有自己所支持的配置文件,配置文件中很 ...
- Vulnhub DC-7靶机渗透
信息搜集 nmap -sP 192.168.146.0/24 #主机发现 nmap -A 192.168.146.144 #端口扫描 查看robots.txt,看看admin,403,其他没有什么可利 ...
- C语言 生日快乐
#include <stdio.h> #include <math.h> #include <stdlib.h> #define I 20 #define R 34 ...
- 如何增加Tomcat内存
有时候在开发中,常常遇到内存溢出问题,很有可能项目过大,导致Tomcat内存不足问题,那么此时就要给Tomcat添加内存了,如,操作如下 1. 先找到Tomcat目录下的catalina.bat文件
- Django ORM操作数据库常用API
昨天晚上,我们完成了一个简单的实例来对数据库表进行操作.今天,我们要熟悉更多的API,实现更复杂的功能.这一步完成了,我们对小型数据的操作问题也就不大了. 现在,我们还是参考django官方文档,来进 ...