聊一聊对“事务”的理解

article/2025/8/19 10:53:43

什么是事务

事务即英文Transaction,在软件开发过程中,难免需要考虑处理事务。从微观层面看亦或者从成员最早了解到这个词汇看,事务通常指多条写入数据库的语句需要并发成功执行,从宏观层面看得话则是客户端发出的并发请求需要一致性并发成功完成,即要么都成功要么都失败。这样以来常见的事务分为了单库事务、分布式事务,当然事务数也演进为了一个衡量服务性能的度量单位,比如在推进性能测试验证时用到的tps指标。

事务的特点

根据事务的定义,可总结出四个特点ACID,即:

原子性(Atomicity): 事务是数据库的逻辑工作单位,事务中包括的诸操作要么全成功,要么全失败。

一致性(Consistency): 事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。当然这个看上去更多是从微观层面提炼的特点描述。

隔离性(Isolation): 一个事务的执行不能被其他事务干扰。

持续性/永久性(Durability): 一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。

事务的控制

事务的控制无非就是对事务的特点进行严格控制以对活动操作的完整准备性提供保障。微观层面的事务控制也是我们最常见的事务控制,无非还是基于数据库层面得。作为Java语言出身的编码人士,此刻第一想到的便是Spring框架中的@Transactional注解,在大多数人看来使用了@Transactional注解即可控制事务以达成特点的要求。然而真的是那样吗,我们还是看看这个注解的描述。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {/*** Alias for {@link #transactionManager}.* @see #transactionManager*/@AliasFor("transactionManager")String value() default "";/*** A <em>qualifier</em> value for the specified transaction.* <p>May be used to determine the target transaction manager, matching the* qualifier value (or the bean name) of a specific* {@link org.springframework.transaction.TransactionManager TransactionManager}* bean definition.* @since 4.2* @see #value* @see org.springframework.transaction.PlatformTransactionManager* @see org.springframework.transaction.ReactiveTransactionManager*/@AliasFor("value")String transactionManager() default "";/*** Defines zero (0) or more transaction labels.* <p>Labels may be used to describe a transaction, and they can be evaluated* by individual transaction managers. Labels may serve a solely descriptive* purpose or map to pre-defined transaction manager-specific options.* <p>See the documentation of the actual transaction manager implementation* for details on how it evaluates transaction labels.* @since 5.3* @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#getLabels()*/String[] label() default {};/*** The transaction propagation type.* <p>Defaults to {@link Propagation#REQUIRED}.* @see org.springframework.transaction.interceptor.TransactionAttribute#getPropagationBehavior()*/Propagation propagation() default Propagation.REQUIRED;/*** The transaction isolation level.* <p>Defaults to {@link Isolation#DEFAULT}.* <p>Exclusively designed for use with {@link Propagation#REQUIRED} or* {@link Propagation#REQUIRES_NEW} since it only applies to newly started* transactions. Consider switching the "validateExistingTransactions" flag to* "true" on your transaction manager if you'd like isolation level declarations* to get rejected when participating in an existing transaction with a different* isolation level.* @see org.springframework.transaction.interceptor.TransactionAttribute#getIsolationLevel()* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setValidateExistingTransaction*/Isolation isolation() default Isolation.DEFAULT;/*** The timeout for this transaction (in seconds).* <p>Defaults to the default timeout of the underlying transaction system.* <p>Exclusively designed for use with {@link Propagation#REQUIRED} or* {@link Propagation#REQUIRES_NEW} since it only applies to newly started* transactions.* @return the timeout in seconds* @see org.springframework.transaction.interceptor.TransactionAttribute#getTimeout()*/int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;/*** The timeout for this transaction (in seconds).* <p>Defaults to the default timeout of the underlying transaction system.* <p>Exclusively designed for use with {@link Propagation#REQUIRED} or* {@link Propagation#REQUIRES_NEW} since it only applies to newly started* transactions.* @return the timeout in seconds as a String value, e.g. a placeholder* @since 5.3* @see org.springframework.transaction.interceptor.TransactionAttribute#getTimeout()*/String timeoutString() default "";/*** A boolean flag that can be set to {@code true} if the transaction is* effectively read-only, allowing for corresponding optimizations at runtime.* <p>Defaults to {@code false}.* <p>This just serves as a hint for the actual transaction subsystem;* it will <i>not necessarily</i> cause failure of write access attempts.* A transaction manager which cannot interpret the read-only hint will* <i>not</i> throw an exception when asked for a read-only transaction* but rather silently ignore the hint.* @see org.springframework.transaction.interceptor.TransactionAttribute#isReadOnly()* @see org.springframework.transaction.support.TransactionSynchronizationManager#isCurrentTransactionReadOnly()*/boolean readOnly() default false;/*** Defines zero (0) or more exception {@linkplain Class classes}, which must be* subclasses of {@link Throwable}, indicating which exception types must cause* a transaction rollback.* <p>By default, a transaction will be rolled back on {@link RuntimeException}* and {@link Error} but not on checked exceptions (business exceptions). See* {@link org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)}* for a detailed explanation.* <p>This is the preferred way to construct a rollback rule (in contrast to* {@link #rollbackForClassName}), matching the exception type, its subclasses,* and its nested classes. See the {@linkplain Transactional class-level javadocs}* for further details on rollback rule semantics and warnings regarding possible* unintentional matches.* @see #rollbackForClassName* @see org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(Class)* @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)*/Class<? extends Throwable>[] rollbackFor() default {};/*** Defines zero (0) or more exception name patterns (for exceptions which must be a* subclass of {@link Throwable}), indicating which exception types must cause* a transaction rollback.* <p>See the {@linkplain Transactional class-level javadocs} for further details* on rollback rule semantics, patterns, and warnings regarding possible* unintentional matches.* @see #rollbackFor* @see org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(String)* @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)*/String[] rollbackForClassName() default {};/*** Defines zero (0) or more exception {@link Class Classes}, which must be* subclasses of {@link Throwable}, indicating which exception types must* <b>not</b> cause a transaction rollback.* <p>This is the preferred way to construct a rollback rule (in contrast to* {@link #noRollbackForClassName}), matching the exception type, its subclasses,* and its nested classes. See the {@linkplain Transactional class-level javadocs}* for further details on rollback rule semantics and warnings regarding possible* unintentional matches.* @see #noRollbackForClassName* @see org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(Class)* @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)*/Class<? extends Throwable>[] noRollbackFor() default {};/*** Defines zero (0) or more exception name patterns (for exceptions which must be a* subclass of {@link Throwable}) indicating which exception types must <b>not</b>* cause a transaction rollback.* <p>See the {@linkplain Transactional class-level javadocs} for further details* on rollback rule semantics, patterns, and warnings regarding possible* unintentional matches.* @see #noRollbackFor* @see org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(String)* @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)*/String[] noRollbackForClassName() default {};}

从定义来看这个注解的属性主要体现在从这么几个方面控制:

1. 作用范围,不仅仅可以添加在方法上面,还可以添加到类级别上。

当注解放在类级别时,表示所有该类的公共方法都配置相同的事务属性信息。如果类级别配置了 @transactional,方法级别也配置了 @transactional,应用程序会以方法级别的事务属性信息来管理事务。

2.作用场景,即在什么情况下提交事务或者回滚事务,将有@Transactional相关的配置参数来决定。

参数名释义举例
value事务管理器设置 Spring 容器中的 Bean 名称,这个 Bean 需要实现接口 PlatformTransactionManager。
isolation事务隔离级别
/*** Use the default isolation level of the underlying datastore.* All other levels correspond to the JDBC isolation levels.* @see java.sql.Connection*/DEFAULT(TransactionDefinition.ISOLATION_DEFAULT),/*** A constant indicating that dirty reads, non-repeatable reads and phantom reads* can occur. This level allows a row changed by one transaction to be read by* another transaction before any changes in that row have been committed* (a "dirty read"). If any of the changes are rolled back, the second* transaction will have retrieved an invalid row.* @see java.sql.Connection#TRANSACTION_READ_UNCOMMITTED*/READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED),/*** A constant indicating that dirty reads are prevented; non-repeatable reads* and phantom reads can occur. This level only prohibits a transaction* from reading a row with uncommitted changes in it.* @see java.sql.Connection#TRANSACTION_READ_COMMITTED*/READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED),/*** A constant indicating that dirty reads and non-repeatable reads are* prevented; phantom reads can occur. This level prohibits a transaction* from reading a row with uncommitted changes in it, and it also prohibits* the situation where one transaction reads a row, a second transaction* alters the row, and the first transaction rereads the row, getting* different values the second time (a "non-repeatable read").* @see java.sql.Connection#TRANSACTION_REPEATABLE_READ*/REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ),/*** A constant indicating that dirty reads, non-repeatable reads and phantom* reads are prevented. This level includes the prohibitions in* {@code ISOLATION_REPEATABLE_READ} and further prohibits the situation* where one transaction reads all rows that satisfy a {@code WHERE}* condition, a second transaction inserts a row that satisfies that* {@code WHERE} condition, and the first transaction rereads for the* same condition, retrieving the additional "phantom" row in the second read.* @see java.sql.Connection#TRANSACTION_SERIALIZABLE*/SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE);

 

propagation事务传播行为
/*** Support a current transaction, create a new one if none exists.* Analogous to EJB transaction attribute of the same name.* <p>This is the default setting of a transaction annotation.*/REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),/*** Support a current transaction, execute non-transactionally if none exists.* Analogous to EJB transaction attribute of the same name.* <p>Note: For transaction managers with transaction synchronization,* {@code SUPPORTS} is slightly different from no transaction at all,* as it defines a transaction scope that synchronization will apply for.* As a consequence, the same resources (JDBC Connection, Hibernate Session, etc)* will be shared for the entire specified scope. Note that this depends on* the actual synchronization configuration of the transaction manager.* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization*/SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),/*** Support a current transaction, throw an exception if none exists.* Analogous to EJB transaction attribute of the same name.*/MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),/*** Create a new transaction, and suspend the current transaction if one exists.* Analogous to the EJB transaction attribute of the same name.* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box* on all transaction managers. This in particular applies to* {@link org.springframework.transaction.jta.JtaTransactionManager},* which requires the {@code javax.transaction.TransactionManager} to be* made available to it (which is server-specific in standard Java EE).* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager*/REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),/*** Execute non-transactionally, suspend the current transaction if one exists.* Analogous to EJB transaction attribute of the same name.* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box* on all transaction managers. This in particular applies to* {@link org.springframework.transaction.jta.JtaTransactionManager},* which requires the {@code javax.transaction.TransactionManager} to be* made available to it (which is server-specific in standard Java EE).* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager*/NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),/*** Execute non-transactionally, throw an exception if a transaction exists.* Analogous to EJB transaction attribute of the same name.*/NEVER(TransactionDefinition.PROPAGATION_NEVER),/*** Execute within a nested transaction if a current transaction exists,* behave like {@code REQUIRED} otherwise. There is no analogous feature in EJB.* <p>Note: Actual creation of a nested transaction will only work on specific* transaction managers. Out of the box, this only applies to the JDBC* DataSourceTransactionManager. Some JTA providers might support nested* transactions as well.* @see org.springframework.jdbc.datasource.DataSourceTransactionManager*/NESTED(TransactionDefinition.PROPAGATION_NESTED);

timeout事务超时时间单位为秒,默认值为-1,当事务超时时会抛出异常,进行回滚操作。
readOnly是否开启只读事务是否开启只读事务,默认 false
rollbackFor回滚事务异常类定义当方法中出异常,且异常类和该参数指定的类相同时,进行回滚操作,否则提交事务。
noRollbackFor非回滚事务异常类定义

指定发生哪些异常不回滚事务,当方法中出异常,且异常类和该参数指定的类相同时,不回滚而是将继续提交事务。

当然@Transactional并非直接加到方法头或者类头上就万事大吉了,还需要了解这么几个潜规则:

1.由于自调用方法不走Spring的代理类,所以无法确保private方法无法受到Spring  AOP的代理,默认为私有private方法设置@Transactional注解无法生效事务。除非使用AspectJ做静态织入,否则需要确保只有public方法才设置@Transactional注解
2.只有异常传播出了标记了@Transactional注解的方法,事务才能遇到异常的情况下回滚,同时需要避免 catch住异常,或者通过TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()手动回滚事务。默认情况下,出现 RuntimeException(非受检异常)或Error的时候,Spring 才会回滚事务,因此我们需要人为的去设置@Transactional(rollbackFor = Exception.class),来突破默认不回滚受检异常的限制
3.默认事务传播策略是REQUIRED,即子方法会复用当前事务,当子方法出异常后会回滚当前事务,导致父方法也无法提交事务。如果不需要这样的效果,则需要人为的修改设置传播方式即propagation参数为REQUIRES_NEW方式的事务传播策略,让子方法运行在独立事务中。

当然还有分布式事务的控制,则显得稍有复杂,待笔者抽时间整理好后再呈现。


http://chatgpt.dhexx.cn/article/Te9CFb05.shtml

相关文章

聊一聊wifi6

引言 8.11&#xff0c;小米十周年&#xff0c;雷军即将召开发布会&#xff0c;相信又是are you ok 放大招的时候了。作为小米各种产品的使用者&#xff08;包括但不限于手机&#xff0c;路由器&#xff0c;音响&#xff0c;手环&#xff0c;中性笔… &#xff09;&#xff0c;…

聊一聊我对测试开发的看法

前言 在一线大厂&#xff0c;没有测试这个岗位&#xff0c;只有测开这个岗位 即使是做业务测试&#xff0c;那么你的title也是测开 所以想聊一聊测开的看法 但不代表这是正确的看法&#xff0c;仅供参考 还没来阿里之前&#xff0c;我对测开的看法 一直以为专职做自动化测…

聊一聊,我对DDD的关键理解

作者&#xff1a;闵大为 阿里业务平台解决方案团队 当我们在学习DDD的过程中&#xff0c;感觉学而不得的时候&#xff0c;可能会问&#xff1a;我们还要学么&#xff1f;这的确引人深思。本文基于工作经验&#xff0c;尝试谈谈对DDD的一些理解。 一、序 《阿甘正传》中&#xf…

聊一聊Kotlin的泛型

Kotlin的泛型 简介 与java一样&#xff0c;kotlin也支持泛型&#xff0c;用法和java泛型差别不大&#xff0c;kotlin特色是型变支持。 基本用法&#xff1a; 定义类&#xff1a; 跟java相同&#xff0c;定义在类后面的尖括号&#xff1a; open class Basket<T>{}定…

聊一聊学习方法

聊一聊学习方法 为什么学习没效果&#xff1f;你只是看起来很努力自知与不自知&#xff0c;真的不是一字之差什么时候真的能出效果&#xff1f;学习方法一&#xff08;拍照式记忆&#xff09;学习方法二&#xff08;殊途同归&#xff09;学习方法三&#xff08;精细化管理&…

聊一聊ThreadLocal内存泄漏的问题

回答任何一个问题的时候应该要遵循&#xff1a;明确题意-->深入浅出-->举例说明-->总结&#xff0c;这四个步骤很重要&#xff0c;可以让你沉着冷静&#xff0c;思路清晰&#xff0c;避免尴尬。 01 — 明确题意 明确题意的意思就是先明确一下面试官的题目&#xff0…

聊一聊Https

前言 https协议是一种在http的基础上进行加密的协议&#xff0c;在http协议传输过程中&#xff0c;传输的数据都是已明文的方式进行传输&#xff0c;那我们的信息就有可能被他人进行捕获篡改&#xff08;比如你给女神表白却被程序员情敌发现并修改了你的消息&#xff0c;然后你…

SLAM基础——聊一聊信息矩阵

文章目录 前言1 :book: 信息矩阵1-1 :bookmark: 信息矩阵是什么&#xff1f;有什么作用&#xff1f;1-2 :bookmark: 信息矩阵与Hessian矩阵的关系1-2-1 Hessian矩阵和H矩阵的关系1-2-2 Hessian或H矩阵和信息矩阵的关系 2 :book: 信息矩阵与最小二乘的关联2-1 :bookmark: 先谈一…

聊一聊SpringCloud的五大组件

聊一聊SpringCloud的五大组件 1.初始SpringCloud 微服务是一种架构方式&#xff0c;最终肯定需要技术架构去实施。 微服务的实现方式很多&#xff0c;但是最火的莫过于Spring Cloud了。为什么&#xff1f; 后台硬&#xff1a;作为Spring家族的一员&#xff0c;有整个Spring全…

聊一聊Serverless

聊一聊Serverless Serverless是什么云计算发展过程Serverless的优势Serverless的不足云函数冷启动热启动函数实例不同语言冷启动时长排名首次调用超时性能优化 SFFBaaS再会推荐阅读 Serverless是什么 从单词角度理解,server译为服务&#xff0c;less译为少&#xff0c;Serverl…

聊一聊C语言位域/位段

目录 1、概念和定义 2、实例 在做嵌入式开发的时候&#xff0c;我们经常会遇到这样的代码&#xff1a; struct {unsigned int widthValidated : 1;unsigned int heightValidated : 1; } status; 这样定义结构体变量是什么意思呢&#xff1f; 主要原因是&#xff1a;有些信…

【毕业季】今天简单聊一聊这几个问题

今天简单聊一聊这几个问题 我又来参加活动啦~ 活动地址&#xff1a;毕业季进击的技术er 首先我看了下活动模板&#xff0c;有三个身份&#xff0c;| 毕业生 | 在校生 |职场人 &#xff0c;现在呢其实我们应该还算是在校生&#xff0c;但是我们是大三&#xff0c;也可以说是大四…

聊一聊差分放大器

目录 1、共模抑制比&#xff08;CMRR&#xff09; 2、低容差电阻 3、高噪声增益 4、单电容滚降 5、运算放大器输入端之间的电容 大学里的电子学课程说明了理想运算放大器的应用&#xff0c;包括反相和同相放大器&#xff0c;然后将它们进行组合&#xff0c;构建差动放大器…

简单聊一聊单点登录

单点登录 一、单点登录二、演示步骤①简单结构(域名的设置)②创建项目1.sso-server 模块代码LoginController代码如下GulimallTestSsoServerApplication启动类代码login.html代码application.properties配置文件pom.xml文件 2.sso-client1模块代码HelloController代码GulimallT…

聊一聊俞敏洪

2009年&#xff0c;CCTV颁发中国经济年度人物&#xff0c;给出了这样的颁奖词&#xff1a; “一个曾经的留级生&#xff0c;让无数学子的人生升级&#xff1b;他从未留过洋&#xff0c;却组建了一支跨国的船队。他用26个字母拉近了此岸和彼岸的距离。胸怀世界&#xff0c;志在东…

闲暇聊一聊

大家好&#xff0c;我是Tom哥 非常庆幸&#xff0c;早毕业了几年&#xff0c;那时的互联网还没有像现在这么卷&#xff0c;甚至没有 内卷 这个网络流行词 一切都是那么美好&#xff0c;可以自由享受学习技术的快乐 Tom哥是校招进的阿里&#xff0c;当时的技术资料可不像现在…

聊一聊数据库的行存与列存

目录 存储方式比较 优缺点比较 行存与列存实验 选择建议 注意事项 好多人最开始学习数据库的时候&#xff0c;是关系数据库&#xff0c;数据以表格形式存储&#xff0c;一行表示一条记录。其实这种就是典型的行存储&#xff08;Row-based store&#xff09;&#xff0c;将…

聊一聊 AS 的一些好用的功能

聊一聊 AS 的一些好用的功能 文章开始前先墨迹几句&#xff0c;好久没写文章了&#xff0c;这段时间公司确实挺忙&#xff0c;也没抽出时间&#xff0c;上一篇文章还是三月初写的&#xff0c;距今已经两个多月啦&#xff0c;不能再这样下去了&#xff0c;虽然我不能像一些大佬…

聊一聊罗振宇

小灰是得到平台的重度用户&#xff0c;也是罗振宇的粉丝。 罗振宇&#xff0c;人称“罗胖子”&#xff0c;非常有趣的是&#xff0c;人们常常把另一个姓罗的胖子和他混为一谈。 今天&#xff0c;我们就来聊一聊他。 罗振宇是个特别复杂的人。 很多人认识罗振宇&#xff0c;是从…

聊一聊我的2020

回顾2020 &#xff08;接下来是一大段唠叨&#xff0c;可以直接到文末&#xff0c;有小安利和经验总结&#xff09; 还有几天2020年就结束并迎来新的一年。这一年中总是能听到有人在感慨2020是不平凡的一年。仔细想想&#xff0c;确实如此&#xff0c;至少对我来说是这样的。 作…