Spring 事务深度解析:核心原理与 12 种事务失效场景全解

作为 Java 后端开发,Spring 事务是我们每天都在使用的核心功能。它通过简单的@Transactional注解,就能让我们轻松实现事务管理,保证数据的一致性。但如果使用不当,@Transactional注解可能会悄无声息地失效,导致数据不一致、脏数据等严重的线上问题。

面试时,Spring 事务更是 100% 的必考题,面试官会从原理到实践层层深挖:

  • Spring 事务的底层原理是什么?
  • @Transactional注解为什么会失效?
  • 事务的 7 种传播行为分别是什么?
  • 什么是事务的隔离级别?解决了什么问题?
  • 同类中方法调用为什么会导致事务失效?

这篇文章,我们就从核心原理、注解配置、失效场景、传播行为、隔离级别五个维度,全面拆解 Spring 事务。不仅会讲清楚理论,更会提供可直接落地的代码示例和最佳实践,让你看完既能轻松应对面试,又能解决实际项目中的事务问题。

一、先搞懂:什么是事务?

事务是一组原子性的 SQL 操作,这组操作要么全部执行成功,要么全部执行失败,不会出现部分成功部分失败的情况。

最经典的例子就是银行转账:A 向 B 转账 100 元,这个操作包含两个步骤:

  1. A 的账户余额减少 100 元
  2. B 的账户余额增加 100 元

如果没有事务,可能会出现 A 的钱扣了,但 B 的钱没加的情况,导致数据不一致。而事务可以保证这两个步骤要么都成功,要么都失败,不会出现中间状态。

事务的 ACID 四大特性

所有的事务都必须满足 ACID 四大特性:

  1. 原子性(Atomicity):事务是一个不可分割的最小单位,所有操作要么全部执行,要么全部不执行
  2. 一致性(Consistency):事务执行前后,数据的完整性约束没有被破坏
  3. 隔离性(Isolation):多个事务并发执行时,每个事务之间相互隔离,互不影响
  4. 持久性(Durability):事务提交后,对数据的修改是永久的,即使系统崩溃也不会丢失

事务的浅显易懂讲解具体在下面文章的前几段 MySQL 事务全解:从 ACID 特性到并发问题,再到底层实现与线上最佳实践https://blog.csdn.net/2401_88151415/article/details/160910978

二、Spring 事务基础

Spring 事务是对 JDBC 事务的封装,它提供了两种事务管理方式:编程式事务声明式事务

1. 编程式事务

编程式事务是通过编写代码来管理事务,需要手动开启事务、提交事务和回滚事务。

java 复制代码
@Autowired
private PlatformTransactionManager transactionManager;

public void transfer(String from, String to, int amount) {
    TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
    try {
        // 扣减A的余额
        accountMapper.decreaseBalance(from, amount);
        // 增加B的余额
        accountMapper.increaseBalance(to, amount);
        // 提交事务
        transactionManager.commit(status);
    } catch (Exception e) {
        // 回滚事务
        transactionManager.rollback(status);
        throw e;
    }
}

优点:灵活,可以精确控制事务的边界

缺点:代码侵入性强,重复代码多,容易出错

2. 声明式事务(推荐)

声明式事务是通过注解或 XML 配置来管理事务,不需要编写任何事务管理的代码。Spring 通过 AOP 动态代理,在方法执行前后自动开启、提交或回滚事务。

java 复制代码
@Transactional
public void transfer(String from, String to, int amount) {
    // 扣减A的余额
    accountMapper.decreaseBalance(from, amount);
    // 增加B的余额
    accountMapper.increaseBalance(to, amount);
}

优点:代码侵入性低,使用简单,便于维护

缺点:灵活性不如编程式事务

核心结论:99% 的业务场景都应该使用声明式事务,只有在需要精确控制事务边界的特殊场景下,才使用编程式事务。

3. 声明式事务的核心原理:AOP 动态代理

声明式事务的底层原理是AOP 动态代理 。当我们给一个方法加上@Transactional注解时,Spring 会为这个类生成一个代理对象,在代理对象的方法执行前后,自动添加事务管理的逻辑。

完整的执行流程:

  1. 客户端调用代理对象的方法
  2. 代理对象在方法执行前,通过事务管理器开启事务
  3. 代理对象执行目标方法
  4. 如果目标方法执行成功,代理对象提交事务
  5. 如果目标方法抛出异常,代理对象回滚事务

Spring 支持两种动态代理方式:

  • JDK 动态代理:基于接口实现,只能代理实现了接口的类
  • CGLIB 动态代理:基于继承实现,可以代理没有实现接口的类

Spring Boot 2.0 以后,默认使用 CGLIB 动态代理。

三、@Transactional注解核心参数详解

@Transactional注解有很多参数,合理配置这些参数可以让事务更符合业务需求。下面是最常用的几个参数:(平时开发最常用的就是指定rollbackFor,其余了解即可

参数 含义 默认值 说明
value/transactionManager 指定事务管理器 当有多个事务管理器时,需要指定使用哪个
propagation 事务传播行为 Propagation.REQUIRED 定义事务之间的嵌套关系
isolation 事务隔离级别 Isolation.DEFAULT 定义多个并发事务之间的隔离程度
timeout 事务超时时间 -1(永不超时) 事务执行超过指定时间后自动回滚
readOnly 是否只读事务 false 标记事务为只读,优化查询性能
rollbackFor 需要回滚的异常类型 RuntimeExceptionError 指定哪些异常会导致事务回滚
noRollbackFor 不需要回滚的异常类型 指定哪些异常不会导致事务回滚

四、12 种常见的事务失效场景(面试必问)

这是本文的核心部分,也是实际项目中最容易踩坑的地方。我整理了 12 种最常见的事务失效场景,每个场景都包含失效原因、错误代码示例、正确代码示例和解决方案

场景 1:方法不是 public 的

失效原因 :Spring 的 AOP 动态代理只能拦截 public 方法,非 public 方法不会被代理,因此@Transactional注解不会生效。

错误示例

java 复制代码
// 错误:private方法,事务不会生效
@Transactional
private void transfer(String from, String to, int amount) {
    accountMapper.decreaseBalance(from, amount);
    accountMapper.increaseBalance(to, amount);
}

正确示例

java 复制代码
// 正确:public方法
@Transactional
public void transfer(String from, String to, int amount) {
    accountMapper.decreaseBalance(from, amount);
    accountMapper.increaseBalance(to, amount);
}

解决方案:所有需要事务的方法都要声明为 public。

场景 2:同类中方法自调用

失效原因:当一个类中的方法调用本类的另一个方法时,调用的是原对象的方法,而不是代理对象的方法,因此不会被 AOP 拦截,事务不会生效。

这是最常见也是最容易被忽略的事务失效场景。

错误示例

java 复制代码
@Service
public class AccountService {

    public void transfer(String from, String to, int amount) {
        // 调用本类的方法,事务不会生效
        doTransfer(from, to, amount);
    }

    @Transactional
    public void doTransfer(String from, String to, int amount) {
        accountMapper.decreaseBalance(from, amount);
        accountMapper.increaseBalance(to, amount);
    }
}

解决方案

1.注入自己的代理对象

java 复制代码
@Service
public class AccountService {

    @Autowired
    private AccountService accountService; // 注入自己的代理对象

    public void transfer(String from, String to, int amount) {
        // 调用代理对象的方法,事务会生效
        accountService.doTransfer(from, to, amount);
    }

    @Transactional
    public void doTransfer(String from, String to, int amount) {
        accountMapper.decreaseBalance(from, amount);
        accountMapper.increaseBalance(to, amount);
    }
}

2.使用AopContext.currentProxy()获取代理对象:

java 复制代码
@Service
public class AccountService {

    public void transfer(String from, String to, int amount) {
        // 获取当前代理对象
        AccountService proxy = (AccountService) AopContext.currentProxy();
        // 调用代理对象的方法,事务会生效
        proxy.doTransfer(from, to, amount);
    }

    @Transactional
    public void doTransfer(String from, String to, int amount) {
        accountMapper.decreaseBalance(from, amount);
        accountMapper.increaseBalance(to, amount);
    }
}

3.将事务方法放到另一个类中

java 复制代码
@Service
public class AccountService {

    @Autowired
    private TransactionService transactionService;

    public void transfer(String from, String to, int amount) {
        transactionService.doTransfer(from, to, amount);
    }
}

@Service
public class TransactionService {

    @Transactional
    public void doTransfer(String from, String to, int amount) {
        accountMapper.decreaseBalance(from, amount);
        accountMapper.increaseBalance(to, amount);
    }
}

场景 3:异常类型不是 RuntimeException 或 Error

失效原因 :Spring 事务默认只会在抛出RuntimeException(运行时异常)和Error(错误)时回滚,对于受检异常(Checked Exception)不会回滚。

受检异常Exception 及其子类(非 RuntimeException),编译强制处理 ,Spring 事务默认不回滚 如

  • Exception(顶级受检异常)
  • IOException(文件读写失败)
  • SQLException(数据库操作错误)
  • ParseException(字符串解析失败)

非受检异常RuntimeException + Error运行时抛出 ,Spring 事务默认自动回滚

  • RuntimeException (运行时异常)
    • 空指针 NullPointerException
    • 数组越界 IndexOutOfBoundsException
    • 算数除零 ArithmeticException
  • Error (系统错误,程序搞不定)
    • 内存溢出 OutOfMemoryError

错误示例

java 复制代码
@Transactional
public void transfer(String from, String to, int amount) throws Exception {
    accountMapper.decreaseBalance(from, amount);
    // 抛出受检异常,事务不会回滚
    throw new Exception("转账失败");
}

解决方案 :在@Transactional注解中指定rollbackFor = Exception.class,让所有异常都触发回滚。

正确示例

java 复制代码
// 正确:指定所有异常都回滚
@Transactional(rollbackFor = Exception.class)
public void transfer(String from, String to, int amount) throws Exception {
    accountMapper.decreaseBalance(from, amount);
    throw new Exception("转账失败");
}

场景 4:手动捕获异常没有抛出

失效原因:如果在方法中手动捕获了异常,并且没有重新抛出,那么 Spring 不会感知到异常,也就不会回滚事务。

错误示例

java 复制代码
@Transactional(rollbackFor = Exception.class)
public void transfer(String from, String to, int amount) {
    try {
        accountMapper.decreaseBalance(from, amount);
        int i = 1 / 0; // 抛出ArithmeticException
        accountMapper.increaseBalance(to, amount);
    } catch (Exception e) {
        // 手动捕获异常,没有抛出,事务不会回滚
        e.printStackTrace();
    }
}

解决方案:捕获异常后重新抛出,或者手动设置事务回滚。

正确示例 1:重新抛出异常

java 复制代码
@Transactional(rollbackFor = Exception.class)
public void transfer(String from, String to, int amount) {
    try {
        accountMapper.decreaseBalance(from, amount);
        int i = 1 / 0;
        accountMapper.increaseBalance(to, amount);
    } catch (Exception e) {
        e.printStackTrace();
        // 重新抛出异常,事务会回滚
        throw e;
    }
}

正确示例 2:手动设置事务回滚

java 复制代码
@Transactional(rollbackFor = Exception.class)
public void transfer(String from, String to, int amount) {
    try {
        accountMapper.decreaseBalance(from, amount);
        int i = 1 / 0;
        accountMapper.increaseBalance(to, amount);
    } catch (Exception e) {
        e.printStackTrace();
        // 手动设置事务回滚
        TransactionStatus status = TransactionAspectSupport.currentTransactionStatus();
        status.setRollbackOnly();
    }
}

场景 5:错误的事务传播行为

失效原因:如果配置了错误的事务传播行为,可能会导致事务不会按照预期的方式执行。

最常见的错误是使用了Propagation.NOT_SUPPORTEDPropagation.NEVER,这两种传播行为会以非事务方式运行。

错误示例

java 复制代码
// 错误:使用NOT_SUPPORTED传播行为,会以非事务方式运行
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void transfer(String from, String to, int amount) {
    accountMapper.decreaseBalance(from, amount);
    accountMapper.increaseBalance(to, amount);
}

解决方案 :根据业务需求选择正确的传播行为,绝大多数场景下使用默认的Propagation.REQUIRED即可。

场景 6:多线程环境

失效原因:Spring 事务是基于线程的,每个线程有自己的事务上下文。如果在方法中开启了新的线程,那么新线程中的操作不会被包含在原事务中。

错误示例

java 复制代码
@Transactional(rollbackFor = Exception.class)
public void transfer(String from, String to, int amount) {
    // 扣减A的余额,在主线程中执行,会被事务管理
    accountMapper.decreaseBalance(from, amount);
    
    // 开启新线程,增加B的余额,不会被事务管理
    new Thread(() -> {
        accountMapper.increaseBalance(to, amount);
    }).start();
    
    // 主线程抛出异常,只会回滚主线程的操作,新线程的操作不会回滚
    throw new RuntimeException("转账失败");
}

解决方案 :不要在事务方法中开启新线程,如果需要异步操作,使用 Spring 的@Async注解,并配置异步事务。

场景 7:数据库不支持事务

失效原因:如果数据库本身不支持事务,那么无论怎么配置 Spring 事务,都不会生效。

最常见的情况是使用 MySQL 的 MyISAM 引擎,MyISAM 引擎不支持事务,只有 InnoDB 引擎支持事务。

解决方案:将数据库表的引擎改为 InnoDB。

复制代码
-- 修改表引擎为InnoDB
ALTER TABLE account ENGINE = InnoDB;

场景 8:方法被 final 或 static 修饰

失效原因

  • final 方法不能被重写,因此无法生成代理对象
  • static 方法属于类,不属于对象,无法被代理

错误示例

java 复制代码
// 错误:final方法,无法被代理,事务不会生效
@Transactional
public final void transfer(String from, String to, int amount) {
    accountMapper.decreaseBalance(from, amount);
    accountMapper.increaseBalance(to, amount);
}

// 错误:static方法,无法被代理,事务不会生效
@Transactional
public static void transfer(String from, String to, int amount) {
    accountMapper.decreaseBalance(from, amount);
    accountMapper.increaseBalance(to, amount);
}

解决方案:不要给事务方法添加 final 或 static 修饰符。

场景 9:类没有被 Spring 管理

失效原因 :如果类没有被 Spring 管理(没有加@Service@Component等注解),那么 Spring 无法为其生成代理对象,事务不会生效。

错误示例

java 复制代码
// 错误:没有加@Service注解,没有被Spring管理
public class AccountService {

    @Transactional
    public void transfer(String from, String to, int amount) {
        accountMapper.decreaseBalance(from, amount);
        accountMapper.increaseBalance(to, amount);
    }
}

解决方案 :给类添加@Service@Component注解,让 Spring 管理这个类。

场景 10:错误的 rollbackFor 属性

失效原因 :如果rollbackFor属性指定的异常类型不对,可能会导致事务不会回滚。

最常见的错误是指定了异常的父类,但抛出的是子类异常,或者反过来。

错误示例

java 复制代码
// 错误:只指定了NullPointerException回滚,但抛出的是ArithmeticException,事务不会回滚
@Transactional(rollbackFor = NullPointerException.class)
public void transfer(String from, String to, int amount) {
    accountMapper.decreaseBalance(from, amount);
    int i = 1 / 0; // 抛出ArithmeticException
    accountMapper.increaseBalance(to, amount);
}

解决方案 :除非有特殊需求,否则统一使用rollbackFor = Exception.class,让所有异常都触发回滚。

场景 11:嵌套事务的坑

失效原因:如果对嵌套事务的传播行为理解不到位,可能会导致事务不会按照预期的方式回滚。

最常见的错误是使用Propagation.REQUIRES_NEW时,内部事务回滚导致外部事务也回滚,或者反过来。

错误示例

java 复制代码
@Service
public class AccountService {

    @Autowired
    private LogService logService;

    @Transactional(rollbackFor = Exception.class)
    public void transfer(String from, String to, int amount) {
        accountMapper.decreaseBalance(from, amount);
        accountMapper.increaseBalance(to, amount);
        // 记录日志,即使日志记录失败,转账也应该成功
        logService.addLog("转账成功");
    }
}

@Service
public class LogService {

    // 错误:使用默认的REQUIRED传播行为,日志记录失败会导致整个转账事务回滚
    @Transactional(rollbackFor = Exception.class)
    public void addLog(String message) {
        logMapper.insert(message);
        throw new RuntimeException("日志记录失败");
    }
}

解决方案 :对于不需要影响外部事务的内部操作,使用Propagation.REQUIRES_NEW传播行为,让内部事务独立运行。

正确示例

java 复制代码
@Service
public class LogService {

    // 正确:使用REQUIRES_NEW传播行为,内部事务独立运行
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void addLog(String message) {
        logMapper.insert(message);
        throw new RuntimeException("日志记录失败");
    }
}

场景 12:事务超时时间设置不合理

失效原因:如果事务执行时间超过了设置的超时时间,事务会自动回滚。如果超时时间设置太短,可能会导致正常的业务操作被回滚。

错误示例

java 复制代码
// 错误:超时时间设置为1秒,业务操作需要2秒,会导致事务自动回滚
@Transactional(timeout = 1, rollbackFor = Exception.class)
public void transfer(String from, String to, int amount) {
    // 模拟耗时2秒的业务操作
    Thread.sleep(2000);
    accountMapper.decreaseBalance(from, amount);
    accountMapper.increaseBalance(to, amount);
}

解决方案:根据业务的实际执行时间,合理设置超时时间。如果不确定,可以使用默认值(永不超时)。

五、事务的 7 种传播行为详解

事务传播行为定义了当一个事务方法被另一个事务方法调用时,事务应该如何传播。Spring 提供了 7 种事务传播行为:

表格

传播行为 含义 说明
REQUIRED(默认) 如果当前没有事务,就创建一个新事务;如果已经有事务,就加入到这个事务中 最常用的传播行为,适合绝大多数场景
REQUIRES_NEW 无论当前有没有事务,都创建一个新的事务 适合内部操作需要独立事务的场景,比如日志记录
NESTED 如果当前有事务,就嵌套在这个事务中运行;如果没有事务,就创建一个新事务 嵌套事务,内部事务回滚不会影响外部事务,外部事务回滚会影响内部事务
SUPPORTS 如果当前有事务,就加入到这个事务中;如果没有事务,就以非事务方式运行 适合查询操作
NOT_SUPPORTED 以非事务方式运行,如果当前有事务,就将当前事务挂起 适合不需要事务的操作
NEVER 以非事务方式运行,如果当前有事务,就抛出异常 严格要求非事务的场景
MANDATORY 如果当前有事务,就加入到这个事务中;如果没有事务,就抛出异常 严格要求在事务中运行的场景

重点讲解三种最常用的传播行为

  1. REQUIRED:默认值,也是最常用的。如果外部方法有事务,内部方法就加入外部事务;如果外部方法没有事务,内部方法就创建一个新事务。
  2. REQUIRES_NEW:总是创建一个新的事务,内部事务和外部事务是独立的。内部事务回滚不会影响外部事务,外部事务回滚也不会影响内部事务。
  3. NESTED:嵌套事务,内部事务是外部事务的一个子事务。内部事务回滚只会回滚自己的操作,不会影响外部事务;但外部事务回滚会导致内部事务也回滚。

六、事务的 4 种隔离级别详解

事务隔离级别定义了多个并发事务之间的隔离程度。隔离级别越高,数据一致性越好,但并发性能越差。

并发事务可能导致的三个问题

  1. 脏读:一个事务读取了另一个事务未提交的数据
  2. 不可重复读:一个事务内两次读取同一数据,结果不一致(因为另一个事务修改了数据并提交)
  3. 幻读:一个事务内两次查询同一范围的数据,结果不一致(因为另一个事务插入了新数据)

4 种隔离级别

表格

隔离级别 脏读 不可重复读 幻读 说明
READ_UNCOMMITTED(读未提交) 最低的隔离级别,允许读取未提交的数据
READ_COMMITTED(读已提交) 只能读取已经提交的数据,解决了脏读问题
REPEATABLE_READ(可重复读) 同一个事务内多次读取同一数据结果一致,解决了脏读和不可重复读问题
SERIALIZABLE(串行化) 最高的隔离级别,所有事务串行执行,解决了所有问题,但性能最差

MySQL 的默认隔离级别是REPEATABLE_READ,Spring 的默认隔离级别是Isolation.DEFAULT,表示使用数据库的默认隔离级别。

七、最佳实践与避坑指南

  1. 优先使用声明式事务:99% 的业务场景都应该使用声明式事务,不要使用编程式事务
  2. 统一配置rollbackFor = Exception.class:让所有异常都触发回滚,避免受检异常不回滚的问题
  3. 避免同类中方法自调用:如果需要调用本类的事务方法,使用代理对象调用
  4. 不要在事务方法中开启新线程:多线程会导致事务失效
  5. 合理设置传播行为和隔离级别:根据业务需求选择合适的传播行为和隔离级别
  6. 事务粒度要尽可能小:不要在事务中执行耗时的操作,比如调用第三方接口、复杂的查询等
  7. 避免大事务:大事务会导致锁等待时间长、回滚慢、数据库连接占用时间长等问题
  8. 测试事务是否生效:在开发阶段,一定要测试事务是否按照预期的方式回滚

八、常见误区纠正

  1. 误区@Transactional注解加在类上,所有方法都会有事务。 纠正:只有 public 方法才会有事务,非 public 方法不会被代理。

  2. 误区 :只要抛出异常,事务就会回滚。 纠正:Spring 默认只会在抛出 RuntimeException 和 Error 时回滚,受检异常不会回滚。

  3. 误区 :同类中方法调用,事务会生效。 纠正:自调用是调用原对象的方法,不是代理对象的方法,事务不会生效。

  4. 误区 :隔离级别越高越好。 纠正:隔离级别越高,并发性能越差。绝大多数场景下,使用数据库默认的隔离级别即可。

  5. 误区 :事务超时时间是从方法执行开始计算的。 纠正:事务超时时间是从事务开始计算的,也就是从数据库连接获取开始计算的。

九、高频面试题解答

  1. 问:Spring 事务的底层原理是什么? 答:Spring 事务的底层原理是 AOP 动态代理。当给方法加上@Transactional注解时,Spring 会为这个类生成一个代理对象,在代理对象的方法执行前后,自动添加事务管理的逻辑。

  2. 问:@Transactional注解为什么会失效? 答:常见的失效原因有:方法不是 public 的、同类中方法自调用、异常类型不对、手动捕获异常没有抛出、错误的传播行为、多线程环境、数据库不支持事务等。

  3. 问:事务的 7 种传播行为分别是什么? 答:7 种传播行为是:REQUIRED、REQUIRES_NEW、NESTED、SUPPORTS、NOT_SUPPORTED、NEVER、MANDATORY。最常用的是 REQUIRED、REQUIRES_NEW 和 NESTED。

  4. 问:事务的 4 种隔离级别分别是什么?解决了什么问题? 答:4 种隔离级别是:READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、SERIALIZABLE。分别解决了脏读、不可重复读和幻读问题。

  5. 问:同类中方法调用为什么会导致事务失效?怎么解决? 答:因为自调用是调用原对象的方法,不是代理对象的方法,不会被 AOP 拦截。解决方案是:注入自己的代理对象、使用 AopContext.currentProxy () 获取代理对象,或者将事务方法放到另一个类中。

  6. 问:编程式事务和声明式事务有什么区别? 答:编程式事务是通过代码手动管理事务,灵活但代码侵入性强;声明式事务是通过注解或 XML 配置管理事务,使用简单但灵活性稍差。绝大多数场景下推荐使用声明式事务。

十、总结

Spring 事务是 Java 后端开发中最常用的功能之一,也是最容易踩坑的功能之一。很多线上的数据不一致问题,都是因为事务使用不当导致的。

本文从核心原理出发,详细讲解了 Spring 事务的实现机制、@Transactional注解的核心参数、12 种常见的事务失效场景、事务的传播行为和隔离级别,最后给出了最佳实践和避坑指南。

记住:事务的本质是保证数据的一致性。在使用事务时,我们不仅要知道怎么用,更要知道为什么这么用,以及可能会遇到什么问题。只有这样,才能写出健壮、可靠的代码,避免线上事故的发生。

相关推荐
SL_staff1 小时前
从Zoom/腾讯会议迁移到私有化会议系统:数据迁移完整方案
java·架构
笨蛋不要掉眼泪1 小时前
Java并发编程:内存可见性与synchronized同步机制
java·开发语言·并发
用户3959924940061 小时前
Java开发者接入大模型API实战:从0到聊天机器人
java
JAVA面经实录9171 小时前
Java 多线程完整版学习文档(无遗漏终版)
java·面试
考虑考虑2 小时前
JDK26中的LazyConstant
java·后端·java ee
Devin~Y2 小时前
互联网大厂 Java 面试实录:JVM、Spring Boot、MyBatis、Redis、Kafka、Spring AI、K8s 全链路追问小Y
java·jvm·spring boot·redis·kafka·mybatis·spring security
摇滚侠2 小时前
SpringCloud 面试题 真正的 offer 偏方 Java 基础 Java 高级
java·spring·spring cloud
tongluowan0072 小时前
Java 内存模型(JMM)- happens-before 与内存屏障
java·内存模型·happens-before
plainGeekDev2 小时前
Android Framework 面试题:Binder都说不清楚,简历别写精通了
android·java