Spring Boot JPA 中transaction的使用

简介: 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个并发过程中可能出现的问题:


  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){
    }
相关文章
|
Java API 数据库
JPA简介:Spring Boot环境下的实践指南
上述内容仅是JPA在Spring Boot环境下使用的冰山一角,实际的实践中你会发现更深更广的应用。总而言之,只要掌握了JPA的规则,你就可以借助Spring Boot无比丰富的功能,娴熟地驾驶这台高性能的跑车,在属于你的程序世界里驰骋。
608 15
|
XML Java 应用服务中间件
Spring Boot 两种部署到服务器的方式
本文介绍了Spring Boot项目的两种部署方式:jar包和war包。Jar包方式使用内置Tomcat,只需配置JDK 1.8及以上环境,通过`nohup java -jar`命令后台运行,并开放服务器端口即可访问。War包则需将项目打包后放入外部Tomcat的webapps目录,修改启动类继承`SpringBootServletInitializer`并调整pom.xml中的打包类型为war,最后启动Tomcat访问应用。两者各有优劣,jar包更简单便捷,而war包适合传统部署场景。需要注意的是,war包部署时,内置Tomcat的端口配置不会生效。
3379 17
Spring Boot 两种部署到服务器的方式
|
SQL Java 编译器
深入理解 Spring Data JPA 的导入与使用:以 UserRepository为例
本文深入解析了 Spring Data JPA 中 `UserRepository` 的导入与使用。通过示例代码,详细说明了为何需要导入 `User` 实体类、`JpaRepository` 接口及 `@Repository` 注解。这些导入语句分别用于定义操作实体、提供数据库交互方法和标识数据访问组件。文章还探讨了未导入时的编译问题,并展示了实际应用场景,如用户保存、查询与删除操作。合理使用导入语句,可让代码更简洁高效,充分发挥 Spring Data JPA 的优势。
928 0
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
1086 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
|
Java 数据库 微服务
微服务——SpringBoot使用归纳——Spring Boot中的项目属性配置——指定项目配置文件
在实际项目中,开发环境和生产环境的配置往往不同。为简化配置切换,可通过创建 `application-dev.yml` 和 `application-pro.yml` 分别管理开发与生产环境配置,如设置不同端口(8001/8002)。在 `application.yml` 中使用 `spring.profiles.active` 指定加载的配置文件,实现环境快速切换。本节还介绍了通过配置类读取参数的方法,适用于微服务场景,提升代码可维护性。课程源码可从 [Gitee](https://gitee.com/eson15/springboot_study) 下载。
912 0
|
Java 数据库连接 API
【Java笔记+踩坑】Spring Data JPA
从常用注解、实体类和各层编写方法入手,详细介绍JPA框架在增删改查等方面的基本用法,以及填充用户名日期、分页查询等高级用法。
【Java笔记+踩坑】Spring Data JPA
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
1449 2
|
缓存 NoSQL Java
Springboot自定义注解+aop实现redis自动清除缓存功能
通过上述步骤,我们不仅实现了一个高度灵活的缓存管理机制,还保证了代码的整洁与可维护性。自定义注解与AOP的结合,让缓存清除逻辑与业务逻辑分离,便于未来的扩展和修改。这种设计模式非常适合需要频繁更新缓存的应用场景,大大提高了开发效率和系统的响应速度。
988 2
|
SQL Java 关系型数据库
Springboot引入jpa来管理数据库
Springboot引入jpa来管理数据库
450 0
Springboot引入jpa来管理数据库
|
SQL Java 数据库连接
springBoot+Jpa(hibernate)数据库基本操作
springBoot+Jpa(hibernate)数据库基本操作
593 0