当前位置: 首页 > news >正文

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

目录

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() { ... }
}

相关文章:

  • JS分支和循环
  • 【LLM】FastAPI入门教程
  • # STM32F103 串口打印配置(HAL库)
  • 应急响应靶机-web2-知攻善防实验室
  • Lyra学习笔记 Experience流程梳理
  • DeepSeek 赋能数字孪生城市,筑牢应急管理智慧防线
  • VLAN的作用和原理
  • 【五子棋在线对战】一.前置知识的了解
  • 吴恩达MCP课程(2):research_server
  • Linux系统下安装配置 Nginx
  • Kanass入门教程- 事项管理
  • 机器视觉2D定位引导-合同要点重度讲解-技术要点及注意事项
  • Java-Character类静态方法深度剖析
  • C语言结构体的别名与创建结构体变量
  • 共享内存-systemV
  • Python 从入门到精通视频下载
  • 各种数据库,行式、列式、文档型、KV、时序、向量、图究竟怎么选?
  • 点云识别模型汇总整理
  • 【Doris基础】Doris中的Replica详解:Replica原理、架构
  • 华为OD机试真题——找出两个整数数组中同时出现的整数(2025A卷:100分)Java/python/JavaScript/C++/C语言/GO六种最佳实现
  • 上海景泰建设股份有限公司网站/最好用的系统优化软件
  • 线下推广平台有哪些/优化外包服务公司
  • 鹤岗做网站/怎么做电商卖东西
  • 重庆涪陵网站建设/站长工具seo
  • 行业app开发公司/百度的关键词优化
  • 庐山网站建设/北京seo平台