spring事务的面试题 —— 事务的特性、传播机制、隔离机制、注解

article/2025/6/10 2:11:00

目录

1、事务的四个特性

2、如何使用事务@Transactional

3、事务的传播机制

3.1 事务传播机制的概念

3.2 事务传播机制的分类

1、PROPAGATION_REQUIRED (默认)

2、PROPAGATION_SUPPORTS

3、PROPAGATION_MANDATORY

4、PROPAGATION_REQUIRES_NEW

5、PROPAGATION_NOT_SUPPORTED

6、PROPAGATION_NEVER

7、PROPAGATION_NESTED

4、事务的隔离机制

4.1 事物隔离机制的概念

4.2 幻读、不可重复读取、脏读的概念

4.3 事务隔离级别

4.4 Spring隔离级别可选值

4.5 spring如何设置隔离级别(代码)

5、事务注解

1. @Transactional (最核心注解)

2.使用范围:


1、事务的四个特性

特性含义作用关键点/并发问题实现机制
原子性事务被视为一个不可分割的最小工作单元。事务中的所有操作要么全部成功执行,要么全部不执行。不存在部分执行的情况。确保操作完整性。例如银行转账的两个操作要么都成功,要么都不生效。强调“不可分割”,没有中间状态。主要通过回滚日志实现,记录事务前状态,失败时恢复到之前的状态。
一致性事务执行的结果必须使数据库从一个一致性状态转换到另一个一致性状态。一致性是指数据满足业务规则和约束。保证数据逻辑正确性和有效性。例如转账前后总金额不变(业务规则)。数据库在事务执行前后都必须处于一致状态;依赖应用层逻辑和数据库约束(主键、外键等)。应用层逻辑 + 数据库约束 + 其他ACID特性(原子性、隔离性、持久性)共同保障。
隔离性多个事务并发执行时,彼此互不影响。每个事务如同独占整个数据库一样执行。防止并发执行导致的数据不一致问题。常见并发问题包括:脏读、不可重复读、幻读。主要通过锁机制和多版本并发控制(MVCC)实现,并提供不同隔离级别供选择(如读未提交、串行化等)。
持久性一旦事务成功提交,它对数据库的修改就是永久性的,即使系统发生故障也不会丢失。确保已提交的事务不会因系统崩溃而丢失,可以恢复到最后一致状态。强调“永久性”。主要通过重做日志(Redo Log)实现,事务提交前先写入日志文件,重启后可依据日志恢复数据。

2、如何使用事务@Transactional

使用事务的注解@Transactional

@EnableTransactionManagement   在启动类上开启全局事务支持

@Transactional注解加在类上,表示这个类中的所有方法都需要事务管理

事务属性的介绍:

1. readOnly = true

  • 含义: 声明事务为只读

  • 默认值: false (读写事务)。


2. rollbackFor = Exception.class

  • 含义: 指定哪些异常类型会触发事务回滚

  • 示例:

    @Transactional(rollbackFor = {SQLException.class, IOException.class})

3. noRollbackFor = {SomeException.class}

  • 含义: 指定哪些异常类型发生时不回滚事务。

  • 示例:

    @Transactional(noRollbackFor = {BusinessValidationException.class})

4. timeout = 10

  • 含义: 设置事务的超时时间(秒)

  • 默认值: 使用底层数据库系统的默认超时(通常无限制)。


5. propagation = Propagation.REQUIRED

  • 含义: 定义事务的传播行为(即当多个事务方法相互调用时,事务如何传递)。

  •  a---调用--->b  b是否能够使用事务的问题


6. isolation = Isolation.DEFAULT

  • 含义: 设置事务的隔离级别(控制并发事务之间的可见性)。

  • 权衡: 隔离级别越高,数据一致性越强,但并发性能越低。

3、事务的传播机制

3.1 事务传播机制的概念

       事务传播描述的事务与事务之间的传播关系, 常见的场景是在一个嵌套调用的方法中,外部方法和内部每个方法都添加了事务管理, 不同的传播行为配置,决定了最终是这些方法是使用同一个事务,还是在不同的事务中运行。

3.2 事务传播机制的分类

传播行为 (Propagation)中文名称核心特性
REQUIRED (默认)必需事务存在事务则加入,不存在则新建事务(最常用)
REQUIRES_NEW新建事务无论是否存在事务,都创建独立新事务(新旧事务完全隔离)
SUPPORTS支持事务存在事务则加入,不存在则以非事务方式运行
MANDATORY强制事务必须存在事务才能执行,否则抛出异常
NOT_SUPPORTED非事务支持强制以非事务方式运行,若存在事务则挂起
NEVER强制非事务必须无事务才能执行,否则抛出异常
NESTED嵌套事务在当前事务内创建嵌套子事务(可独立回滚,依赖数据库 Savepoint 机制)

1、PROPAGATION_REQUIRED (默认)

支持当前事务,如果当前已经存在事务,就加入到事务中执行,如果当前没有事务,就新建一个事务。这是最常见的选择。

public class Demo{void a(){b();//新建事务}@Transactionalvoid a(){b(); //使用a的事务}@Transactionalvoid b();}

2、PROPAGATION_SUPPORTS

支持当前事务,如果当前没有事务,就以非事务方式执行。

public class Demo{void a(){b();//不要事务}@Transactionalvoid a(){b(); //使用a的事务}@Transactionalvoid b();}

3、PROPAGATION_MANDATORY

支持当前事务,如果当前没有事务,就抛出异常。

public class Demo{void a(){b();//报错}@Transactionalvoid a(){b(); //使用a的事务}@Transactionalvoid b();}

4、PROPAGATION_REQUIRES_NEW

新建事务,如果当前存在事务,把当前事务挂起。

public class Demo{void a(){b();//新建}@Transactionalvoid a(){b(); //挂起a事务 新建事务}@Transactionalvoid b();}

5、PROPAGATION_NOT_SUPPORTED

以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

public class Demo{void a(){b(); }@Transactionalvoid a(){b(); //挂起a事务}@Transactionalvoid b();}

6、PROPAGATION_NEVER

以非事务方式执行,如果当前存在事务,则抛出异常。

public class Demo{void a(){b(); }@Transactionalvoid a(){b(); //报错}@Transactional(传播级别)void b();}

7、PROPAGATION_NESTED

如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。

嵌套事务: 与REQUIRED不同, NESTED支持真正意义上的子事务, 父事务回滚会将所有子事务都回滚,子事务回滚不会引起父事务的回滚。而REQUIRED其实只有一个物理事务。

public class Demo{void a(){b(); //新建}@Transactional  父事务void a(){b(); // 新建事务  子事务}@Transactional(传播级别)void b();}

4、事务的隔离机制

4.1 事物隔离机制的概念

       事务的隔离级别描述的是多个事务之间的可见性问题。比如一个事务还未提交时,其他事务是否能看到被未提交事务修改的数据。

4.2 幻读、不可重复读取、脏读的概念

问题类型脏读不可重复读幻读(虚读)
现象描述事务读取了其他未提交事务修改的数据。同一事务中多次读取同一记录,结果不同(因为其他事务已提交更新)。同一事务中多次查询返回的记录数量不同(插入或删除导致)。
示例说明T1 更新记录但未提交,T2 读取该记录,之后 T1 回滚,T2 读取到无效数据。T1 读取某记录,T2 更新并提交该记录,T1 再次读取发现数据变化。T1 查询是否存在某记录,结果为无;准备插入时,T2 插入该记录并提交,T1 插入失败或删除成功却找不到记录。
允许的并发操作一个事务在另一个事务未提交时可以读取其修改的数据一个事务在另一个事务提交后可以读取其更新的数据一个事务在另一个事务提交后可以插入/删除记录影响查询结果集
数据状态未提交数据已提交的修改数据已提交的新增/删除数据
操作类型读未提交UPDATE读已提交UPDATE读已提交INSERT/DELETE
影响范围单行数据单行数据多行结果集
根本原因事务隔离失效数据版本变更数据集范围变化
导致结果读到了“脏”数据(无效、可能被回滚的数据)同一条记录在同一个事务中读取不一致同一范围查询返回不同的行数(像是“幻觉”出现或消失)

4.3 事务隔离级别

隔离级别别名描述可能出现的并发问题是否加锁应用场景说明
读未提交Read Uncommitted事务可以读取其他事务未提交的数据。脏读、不可重复读、幻读最低隔离级别,性能最好但数据一致性最差,实际很少使用。
读已提交Read Committed事务只能读取已经提交的数据,避免脏读。不可重复读、幻读多数数据库默认级别(除MySQL外),适用于对一致性要求不高的场景。
可重复读Repeatable Read在同一个事务中多次读取的结果一致,InnoDB引擎的默认隔离级别。会出现“幻读”现象。幻读是(范围锁)MySQL默认级别,保证同一查询结果不变,但可能插入新记录导致幻读。
串行化Serializable所有事务串行执行,通过锁表来强制事务串行化,避免所有并发问题。是(表锁)最高隔离级别,安全性最高,但性能差,容易产生锁竞争和超时,实际应用较少使用。
  • Mysql默认隔离级别:REPEATABLE-READ 可重复读
  • Oracle默认隔离级别:Read committed 读已提交

4.4 Spring隔离级别可选值

隔离级别说明
ISOLATION_DEFAULT(默认级别)这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.
ISOLATION_READ_UNCOMMITTED(读未提交)这是事务最低的隔离级别,它允许另外一个事务可以看到这个事务未提交的数据。 这种隔离级别会产生脏读,不可重复读和幻像读。
ISOLATION_READ_COMMITTED(读已提交)保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。 这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读(因为在事务提交前允许别的事务更新和插入操作)。
ISOLATION_REPEATABLE_READ(可重复读)它保证了一个事务不能修改已经由另一个事务读取但还未提交的数据,也就是说同一个事务内读取的数据都是一致的。这种事务隔离级别可以防止脏读、不可重复读。但是可能出现幻像读(一个事务在提交前不允许别的事务更新,但是允许插入)。
ISOLATION_SERIALIZABLE(串行化)这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。 除了防止脏读,不可重复读外,还避免了幻像读(一个事务在提交前不允许别的事务读取、更新、插入)。

4.5 spring如何设置隔离级别(代码)

注解

@Transactional(isolation = Isolation.REPEATABLE_READ,propagation = Propagation.REQUIRED,timeout = 5000,readOnly = true,rollbackFor = Exception.class,noRollbackFor = NullPointerException.class)

示例代码:

@RequestMapping("/transfer")
public Object transfer(Integer fromId, Integer toId, Double money){//接收数据,传递数据到业务层boolean flag = accountService.transfer(fromId, toId, money);//返回结果给客户端return flag;
}
@RequestMapping("/findById")
public void findAccountById(Integer id){accountService.query(id);
}
public interface AccountService {public boolean transfer(Integer fromId, Integer toId, double money);
​public void query(Integer id);
​
}
package com.hl.springboot4.service;
​
import com.hl.springboot4.dao.AccountDao;
import com.hl.springboot4.pojo.Account;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
/*
@EnableTransactionManagement 开启全局事务支持
@Transactional 使用事务readOnly = true, 只读事务  当前事务中查询出的数据,不能用户更新操作rollbackFor = Exception.class  当遇到特定异常,执行rollback回滚noRollbackFor = {} 当发生某种异常,不回滚timeout=数值   超时时间propagation =  事务的传播机制  a--调用-->b b是否能够使用事务的问题Propagation.REQUIREDisolation =  事务的隔离行为  两个方法在使用事务时,对方操作的数据是否可见*/
@Service
@Transactional(isolation = Isolation.SERIALIZABLE)
public class AccountServiceImpl implements AccountService{@Autowiredprivate AccountDao accountDao;@Override
//    @Transactional//事务注解public boolean transfer(Integer fromId, Integer toId, double money) {//转出方法int num1 = accountDao.transferOut(fromId,money);
//        System.out.println(1/0);//转入方法int num2 = accountDao.transferIn(toId,money);return num1==num2&&num1>0 ? true : false;}
/*事务隔离机制:isolation = Isolation.READ_UNCOMMITTEDREAD_UNCOMMITTED 读未提交  读取到其他事务修改但是尚未提交的数据  可能出现脏数据READ_COMMITTED 读已提交 读取其他事务已经提交的数据REPEATABLE_READ 可重复读  一个事务在执行期间,不受其他会话影响,多次读取结果保持一致SERIALIZABLE 可串行化  锁表  第一个事务commit提交后,第二个事务才能执行*/@Overridepublic void query(Integer id) {Account account = accountDao.getAccountById(id);System.out.println(account);
​Account account2 = accountDao.getAccountById(id);System.out.println(account);System.out.println(account2);}
}
package com.hl.springboot4.dao;
​
import com.hl.springboot4.pojo.Account;
​
public interface AccountDao {//转出public int transferOut(Integer fromId,Double money);//转入public int transferIn(Integer toId,Double money);//查询public Account getAccountById(Integer id);
}
package com.hl.springboot4.dao;
​
import com.hl.springboot4.pojo.Account;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.RequestMapping;
​
import java.util.List;
​
@Repository
public class AccountDaoImpl implements AccountDao{@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic int transferOut(Integer fromId, Double money) {String sql = "update account set money = money - ? where id = ?";return jdbcTemplate.update(sql, money, fromId);}
​@Overridepublic int transferIn(Integer toId, Double money) {String sql = "update account set money = money + ? where id = ?";return jdbcTemplate.update(sql, money, toId);}
​@Overridepublic Account getAccountById(Integer id) {String sql = "select * from account where id = ?";List<Account> list = jdbcTemplate.query(sql,new BeanPropertyRowMapper<Account>(Account.class),id);return list!=null ? list.get(0) : null;}
}
@SpringBootTest
class Springboot4ApplicationTests {@Autowiredprivate AccountController accountController;@Testvoid tes1() {accountController.findAccountById(1);}@Testvoid tes2() {accountController.transfer(1,2,300.0);}
​
}

5、事务注解

1. @Transactional (最核心注解)

属性说明示例
value/transactionManager指定事务管理器 Bean 名称(多数据源时必填)@Transactional("orderTxManager")
propagation事务传播行为(默认 Propagation.REQUIREDpropagation = Propagation.REQUIRES_NEW
isolation事务隔离级别(默认 Isolation.DEFAULTisolation = Isolation.READ_COMMITTED
timeout事务超时时间(秒),-1 表示永不超时timeout = 30
readOnly是否只读事务(默认 falsereadOnly = true
rollbackFor触发回滚的异常类型(数组)rollbackFor = {SQLException.class}
noRollbackFor不触发回滚的异常类型(数组)noRollbackFor = NullPointerException.class
label事务标签(Spring 5.3+ 用于添加描述性标签)label = "order-service"

2.使用范围

@Transactional // 类级:所有public方法生效
@Service
public class OrderService {@Transactional(propagation = Propagation.REQUIRES_NEW) // 方法级:覆盖类配置public void createOrder() { ... }
}


http://www.hkcw.cn/article/oqDnZnhyfD.shtml

相关文章

以色列将阻止中东国家外长代表团访问约旦河西岸 会议面临取消

当地时间5月31日,一位以色列官员表示,以色列不会允许原定于在约旦河西岸城市拉姆安拉举行的阿拉伯外交部长会议召开。同一天,巴勒斯坦民族权力机构官员表示,关于周日的会议是否能够举行的问题仍在讨论中。据《以色列时报》报道,一名以色列高级官员证实,以方决定阻止中东国…

克瓦拉茨赫利亚:加盟巴黎是正确的选择,梦想成真

北京时间6月1日,巴黎圣日耳曼夺得了队史首座欧冠冠军。赛后,克瓦拉茨赫利亚接受了TNT体育的采访。他表达了难以置信的情绪:“这太疯狂了。我无法想象今天我成为了欧洲冠军联赛的冠军。梦想成真,这种情绪简直无法形容。”克瓦拉茨赫利亚自豪地披着格鲁吉亚国旗,他表示:“我…

特朗普为何支持日铁收购美国钢铁 政治博弈下的变脸艺术

这年头的政治戏码堪比好莱坞大片。还记得去年底特朗普在社交媒体上的惊天咆哮吗?“美国钢铁必须姓美!”这位曾经高喊“美国优先”的民族主义者,转眼间变成了跨国资本的代言人。五个月内,特朗普从强烈反对日本制铁收购美国钢铁公司,到大力支持并声称这项交易能创造7万个岗位…

网友喊话佛山龙舟队帮帮辽宁队 房东队的传承与拼搏

去年端午节,广东佛山沙步龙船队因队员黎国添的发言在网络上走红,被网友戏称为“房东队”。今年5月27日,九派新闻现场观看了沙步龙船队的传统仪式“拜大廟”,并采访了黎国添。他不仅是沙步经济社社长,还是十几套房的房东以及一家光伏发电公司的老板。黎国添表示,虽然队伍中…

专家谈中国向韩国开放稀土供应 博弈策略显现

美国一直关注的稀土资源被中国严格管控,这让美国感到十分困扰。然而,中国却向韩国开放了部分稀土供应,这是中美博弈中的一步棋。此前有猜测认为,中国为了换取美国降低关税可能会放松稀土出口。但到了5月中旬,中国对稀土出口审批流程变得更加严格,主要针对的是美国。由于无…

加沙近1岁孩子只有3.9公斤 饥荒危机加剧

以色列今年3月重新封锁加沙地带并恢复军事行动,导致当地民众严重缺乏基本生活物资,面临饥荒。加沙母亲扎伊塔尔表示,她经常领不到物资援助,11个月大的儿子体重只有3.9公斤,不到正常孩子的三分之一,已被诊断为严重营养不良。尽管20天前他们获得了医疗撤离许可,但她仍在等…

东风日产N7累计大定17215台 黑马车型强势崛起

东风日产官方发布海报显示,日产N7累计大定已达17215台,成为国内中大型轿车的黑马车型。该车于4月27日上市,共推出5款车型,售价区间为11.99-14.99万元。新车车长4930mm,轴距2915mm,是一款中大型纯电轿车,车身尺寸配置与比亚迪汉相似。起售价仅为11.99万元,顶配不到15万,…

今起试行!中国单方面免签“朋友圈”再增5国 拉美国家首次纳入

今天起,中国对巴西、阿根廷、智利、秘鲁、乌拉圭五国持普通护照人员试行免签政策,中国单方面免签“朋友圈”再添新成员。2025年6月1日至2026年5月31日期间,这五个国家的公民来华经商、旅游观光、探亲访友、交流访问或过境不超过30天时,可免办签证入境。这是中方首次将免签政…

纳赛尔:把欧冠冠军献给故去的母亲,梦想成真夜

北京时间6月1日凌晨,2024-2025赛季欧冠决赛在慕尼黑举行,巴黎圣日耳曼以5-0大胜国际米兰,赢得了队史首座欧冠冠军。赛后,巴黎主席纳赛尔在混采区接受了采访。他表示,当晚他要和欧冠奖杯一起睡,这是一个梦想,他感到非常自豪。他还表示要把这场胜利献给已经去世的母亲,她…

小红书 发评论 分析 x-s x-t

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 逆向过程 部分Python代码 ck jso…

Python打卡训练营Day41

DAY 41 简单CNN 知识回顾 数据增强卷积神经网络定义的写法batch归一化&#xff1a;调整一个批次的分布&#xff0c;常用与图像数据特征图&#xff1a;只有卷积操作输出的才叫特征图调度器&#xff1a;直接修改基础学习率 卷积操作常见流程如下&#xff1a; 1. 输入 → 卷积层 →…

樊振东为何加盟德国乒乓球俱乐部 欧洲冒险新挑战

樊振东在社交媒体上发布了一张观看欧冠比赛的照片,引发了球迷对他欧洲之行目的的猜测。紧接着,德国乒乓球甲级联赛FC萨尔布吕肯俱乐部宣布,奥运冠军樊振东将加盟球队。俱乐部官方公告表示,前世界排名第一、国际乒坛巨星之一的樊振东将在新赛季代表球队出战德国乒乓球甲级联…

被认定正当防卫两年后申请128万国赔 正义迟来引发热议

近日,“海南七旬老人救孙砍伤酒后闹事者”事件有了新动态,令人揪心。2025年5月19日,杨成杰在被认定正当防卫的两周年之际提交国家赔偿申请,两天后海南省第二中级人民法院迅速受理,引发社会各界广泛关注与热议。回溯到2017年8月31日,这一天改变了杨成杰的命运。同村的杨某…

一德克士店长用消费券套现13.7万 骗取补贴被判刑

在消费刺激政策不断发力的背景下,政府发放消费券旨在拉动内需、惠及民生。然而,这一暖心之举却被人钻了空子。5月29日下午,上海市松江区人民法院公开审理了一起政府消费券补贴诈骗案,为那些妄图钻空子的人敲响警钟。案件主角是德克士门店的一位店长夏某。2024年,上海推出了…

余华说50%以上鸡汤语都不是他说的 伪语录泛滥引发关注

余华打假网络鸡汤,称超过50%的语录都不是他说的。网友调侃建议他开直播,为写作文积累素材。近年来,余华频繁登上热搜,两年间共上四十多次热搜,成为文坛网红。他的走红原因在于幽默感和反差萌。尽管作品如《活着》、《许三观卖血记》等题材沉重严肃,但他在采访中却极其风趣…

童年照 雷军晒“三条杠”旧照

6月1日儿童节,雷军发文祝所有小朋友都有一个快乐的童年。随后,他晒出了自己的童年照,并配文“三条杠”。照片中的小雷军手捧着花,花上写着“光荣”二字,胳膊上佩戴着三条杠的标志。网友热议纷纷:“这孩子以后有出息”“我掐指一算,此人日后必成大器”“祝小雷同学儿童节…

媒体人辣评《歌手》第三期 选曲策略成胜负关键

随着《歌手2025》第二期节目的热度未减,第三期的网传歌单已在各大社交平台引发热议。这份尚未得到官方确认的歌单不仅展示了歌手们挑战自我的勇气,还暗示了激烈的淘汰危机。单依纯可能在本期节目中挑战林忆莲的高难度作品《归零》或《纤维》,这两首歌曲对气息控制和情感表达…

陈小春演唱会首场郑伊健做特别嘉宾 古惑仔兄弟同框引“爷青回”

5月31日,陈小春在上海举办生旦净末丑巡演首站,郑伊健作为嘉宾惊喜登场。两人合唱了《一起冲一起闯》,古惑仔兄弟再次同框让不少观众感叹“爷青回”。郑伊健还清唱了一段《友情岁月》,感动得陈小春落泪。1996年,陈小春与郑伊健因电影《古惑仔之人在江湖》结缘,二人饰演的“…

专家解读马克龙为何到亚太来演讲 暗流涌动的外交棋局

马克龙访问印尼的行程表面上看似寻常,实际上却暗藏玄机。他此行不仅仅是进行简单的贸易和安全合作,背后可能还有更深层次的战略考量。法国总统出现在东南亚大国,是否仅仅是为了军火交易?还是说这背后隐藏着更多复杂的政治意图?法国与印尼的互动远不止表面的贸易和联合军演…

小车被两辆大货车挤扁 司机爬出 安全问题不容忽视

5月29日,浙江温州赤溪隧道附近发生了一起交通事故,迅速在网上引起关注。根据行车记录仪的画面,下午三点左右,事故发生在一个红绿灯路口,交警已在现场处理,周围聚集了一些司机和行人。事故现场紧张,小车后部严重变形,几乎失去了原来的轮廓。一辆货车以相当快的速度追尾了…