Spring事务详解

文章目录

  • 一、开篇:从生活中的转账说起
  • 二、什么是事务?
    • [2.1 ACID特性通俗解释](#2.1 ACID特性通俗解释)
  • 三、Spring事务的核心作用
  • 四、声明式事务实现方式
    • [4.1 @Transactional注解详解](#4.1 @Transactional注解详解)
    • [4.2 @Transactional核心属性](#4.2 @Transactional核心属性)
  • 五、事务传播行为(7种传播机制)
    • [5.1 REQUIRED(默认值)](#5.1 REQUIRED(默认值))
    • [5.2 REQUIRES_NEW](#5.2 REQUIRES_NEW)
    • [5.3 SUPPORTS](#5.3 SUPPORTS)
    • [5.4 NOT_SUPPORTED](#5.4 NOT_SUPPORTED)
    • [5.5 MANDATORY](#5.5 MANDATORY)
    • [5.6 NEVER](#5.6 NEVER)
    • [5.7 NESTED](#5.7 NESTED)
  • 六、@Transactional失效的12种可能性
    • [6.1 方法访问权限非public](#6.1 方法访问权限非public)
    • [6.2 方法被final修饰](#6.2 方法被final修饰)
    • [6.3 方法被static修饰](#6.3 方法被static修饰)
    • [6.4 同一个类中的自调用](#6.4 同一个类中的自调用)
    • [6.5 异常被捕获未重新抛出](#6.5 异常被捕获未重新抛出)
    • [6.6 异常类型不匹配](#6.6 异常类型不匹配)
    • [6.7 数据库引擎不支持事务](#6.7 数据库引擎不支持事务)
    • [6.8 事务传播机制设置不当](#6.8 事务传播机制设置不当)
    • [6.9 多线程调用](#6.9 多线程调用)
    • [6.10 事务管理器配置错误](#6.10 事务管理器配置错误)
    • [6.11 类未被Spring管理](#6.11 类未被Spring管理)
    • [6.12 代理机制限制](#6.12 代理机制限制)
  • 七、事务失效问题排查清单
  • 八、面试常考:核心要点总结
    • [8.1 Spring事务核心问题](#8.1 Spring事务核心问题)
    • [8.2 事务传播行为记忆口诀](#8.2 事务传播行为记忆口诀)
    • [8.3 最佳实践建议](#8.3 最佳实践建议)
    • [8.4 高级面试题](#8.4 高级面试题)

一、开篇:从生活中的转账说起

想象这样一个场景:你要给朋友转账100元,整个转账过程其实包含两个步骤:

  1. 从你的账户扣减100元
  2. 给朋友的账户增加100元

如果第一步成功了,但第二步因为网络异常失败了,会发生什么?你的钱少了,朋友没收到,这笔钱就"消失"了!这就是没有事务保护带来的严重问题。

事务就是为了解决这类问题而生的。它就像一个"保险箱",把多个操作打包在一起,要么全部成功,要么全部失败,保证数据的一致性。

二、什么是事务?

在数据库领域,事务(Transaction)是一个最小的不可分割的工作单位。事务必须具备ACID四大特性:

2.1 ACID特性通俗解释

特性 含义 生活比喻
原子性(Atomicity) 事务中的操作要么全部成功,要么全部失败 就像买彩票,要么中奖全拿走,要么不中奖什么都不拿
一致性(Consistency) 事务执行前后,数据库从一个一致性状态转变到另一个一致性状态 就像天平,两边始终保持平衡
隔离性(Isolation) 多个事务并发执行时,互不干扰 就像在银行办理业务的独立窗口
持久性(Durability) 事务一旦提交,对数据的修改就是永久的 就像刻在石头上的字,风吹雨打都不会消失

三、Spring事务的核心作用

Spring事务管理框架是对数据库事务的封装和增强,主要提供以下核心价值:

  1. 简化开发:通过声明式事务,无需手动编写复杂的事务管理代码
  2. 统一管理:将事务逻辑从业务代码中分离,实现关注点分离
  3. 灵活配置:支持编程式和声明式两种事务管理方式
  4. 跨数据源支持:可以管理多个数据源的事务操作

核心优势:让开发者专注于业务逻辑,而将事务管理的复杂性交给Spring框架处理。

四、声明式事务实现方式

4.1 @Transactional注解详解

@Transactional是Spring最常用的事务注解,它可以作用在类或方法上。

java 复制代码
// 基本用法示例
@Service
public class AccountService {
    
    @Autowired
    private AccountDao accountDao;
    
    // 方法级别事务
    @Transactional
    public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
        // 扣款
        accountDao.decrease(fromId, amount);
        // 模拟异常,测试事务回滚
        if (amount.compareTo(new BigDecimal("10000")) > 0) {
            throw new RuntimeException("单次转账金额不能超过10000元");
        }
        // 收款
        accountDao.increase(toId, amount);
    }
}

4.2 @Transactional核心属性

java 复制代码
@Transactional(
    propagation = Propagation.REQUIRED,  // 传播行为
    isolation = Isolation.READ_COMMITTED,  // 隔离级别
    timeout = 30,  // 超时时间(秒)
    readOnly = false,  // 是否只读
    rollbackFor = Exception.class,  // 指定回滚异常
    noRollbackFor = NullPointerException.class  // 指定不回滚异常
)

属性详解

  • propagation:事务传播行为,决定多个事务方法相互调用时如何执行
  • isolation:事务隔离级别,控制并发事务之间的干扰程度
  • timeout:事务超时时间,超过指定时间自动回滚
  • readOnly:设置为true时表示只读事务,可优化查询性能
  • rollbackFor:指定哪些异常触发回滚
  • noRollbackFor:指定哪些异常不触发回滚

五、事务传播行为(7种传播机制)

事务传播行为定义了多个事务方法相互调用时,事务如何传播。Spring提供了7种传播机制,我们通过具体场景来理解:

5.1 REQUIRED(默认值)

场景:方法A调用方法B,如果A有事务,B就加入A的事务;如果A没有事务,B就创建新事务。

java 复制代码
@Service
public class OrderService {
    
    @Autowired
    private PaymentService paymentService;
    
    @Transactional(propagation = Propagation.REQUIRED)
    public void createOrder(Order order) {
        // 创建订单
        orderDao.save(order);
        // 调用支付服务,会加入当前事务
        paymentService.processPayment(order);
    }
}

@Service
public class PaymentService {
    
    @Transactional(propagation = Propagation.REQUIRED)
    public void processPayment(Order order) {
        // 支付处理,与createOrder在同一个事务中
        paymentDao.deduct(order.getUserId(), order.getAmount());
    }
}

5.2 REQUIRES_NEW

场景:方法B总是创建新事务,如果A有事务,A的事务会被挂起。

java 复制代码
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logOperation(String operation) {
    // 总是创建新事务,独立记录日志
    logDao.save(operation);
}

使用场景:日志记录、审计信息等需要独立事务的场景。

5.3 SUPPORTS

场景:如果调用者有事务就加入,没有就以非事务方式执行。

java 复制代码
@Transactional(propagation = Propagation.SUPPORTS)
public User findUserById(Long userId) {
    return userDao.findById(userId);
}

使用场景:查询方法,无论是否有事务都能正常执行。

5.4 NOT_SUPPORTED

场景:总是以非事务方式执行,如果调用者有事务,调用者事务会被挂起。

java 复制代码
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void sendEmail(String to, String content) {
    // 发送邮件,不使用事务
    emailService.send(to, content);
}

5.5 MANDATORY

场景:必须在事务中执行,如果调用者没有事务就抛出异常。

java 复制代码
@Transactional(propagation = Propagation.MANDATORY)
public void criticalOperation() {
    // 必须在事务中执行,否则抛出异常
    businessDao.update();
}

5.6 NEVER

场景:总是以非事务方式执行,如果调用者有事务就抛出异常。

java 复制代码
@Transactional(propagation = Propagation.NEVER)
public void cacheRefresh() {
    // 刷新缓存,不能在事务中执行
    cacheManager.refresh();
}

5.7 NESTED

场景:如果调用者有事务,就嵌套事务执行;如果没有,就创建新事务。

java 复制代码
@Transactional(propagation = Propagation.NESTED)
public void batchInsert(List<User> users) {
    // 嵌套事务,可以独立回滚
    for (User user : users) {
        userDao.save(user);
    }
}

关键区别:嵌套事务可以独立回滚,但不影响外部事务。

六、@Transactional失效的12种可能性

6.1 方法访问权限非public

问题代码

java 复制代码
@Service
public class UserService {
    
    // private方法,事务失效
    @Transactional
    private void saveUser(User user) {
        userDao.save(user);
    }
    
    // protected方法,事务失效
    @Transactional
    protected void updateUser(User user) {
        userDao.update(user);
    }
    
    // package-private方法,事务失效
    @Transactional
    void deleteUser(Long id) {
        userDao.delete(id);
    }
}

原因:Spring的AOP代理机制要求目标方法必须是public的,因为代理类需要重写该方法。private、protected、package-private方法无法被代理,所以事务失效。

解决方案:将方法访问权限改为public。

6.2 方法被final修饰

问题代码

java 复制代码
@Service
public class UserService {
    
    // final方法,事务失效
    @Transactional
    public final void saveUser(User user) {
        userDao.save(user);
    }
}

原因:final修饰的方法不能被重写,而Spring的AOP代理是通过动态代理(JDK动态代理或CGLIB)生成代理类并重写方法来实现的。final方法无法被重写,导致代理无法生成,事务失效。

解决方案:不要用final修饰需要事务的方法。

6.3 方法被static修饰

问题代码

java 复制代码
@Service
public class UserService {
    
    // static方法,事务失效
    @Transactional
    public static void saveUser(User user) {
        userDao.save(user);
    }
}

原因:static方法属于类而不是对象,无法被代理。Spring的事务管理是基于对象级别的代理,static方法无法通过代理增强,所以事务失效。

解决方案:不要用static修饰需要事务的方法。

6.4 同一个类中的自调用

问题代码

java 复制代码
@Service
public class OrderService {
    
    @Transactional
    public void createOrder(Order order) {
        // 创建订单
        orderDao.save(order);
        // 直接调用同类方法,事务失效
        this.saveOrderItems(order.getItems());
    }
    
    @Transactional
    public void saveOrderItems(List<OrderItem> items) {
        for (OrderItem item : items) {
            orderItemDao.save(item);
        }
    }
}

原因 :Spring的事务是基于AOP代理实现的,当在同一个类中通过this直接调用方法时,调用的是原始对象的方法,而不是经过代理增强的方法,所以事务失效。

解决方案

java 复制代码
// 方案1:注入自身调用
@Service
public class OrderService {
    
    @Autowired
    private OrderService self;  // 注入自身
    
    @Transactional
    public void createOrder(Order order) {
        orderDao.save(order);
        // 通过代理对象调用,事务生效
        self.saveOrderItems(order.getItems());
    }
    
    @Transactional
    public void saveOrderItems(List<OrderItem> items) {
        for (OrderItem item : items) {
            orderItemDao.save(item);
        }
    }
}

// 方案2:提取到不同Service
@Service
public class OrderService {
    
    @Autowired
    private OrderItemService orderItemService;
    
    @Transactional
    public void createOrder(Order order) {
        orderDao.save(order);
        // 调用不同Service的方法,事务生效
        orderItemService.saveOrderItems(order.getItems());
    }
}

6.5 异常被捕获未重新抛出

问题代码

java 复制代码
@Service
public class PaymentService {
    
    @Transactional
    public void processPayment(Payment payment) {
        try {
            // 支付处理
            accountDao.deduct(payment.getUserId(), payment.getAmount());
            // 模拟异常
            if (payment.getAmount().compareTo(new BigDecimal("10000")) > 0) {
                throw new RuntimeException("金额超限");
            }
            accountDao.credit(payment.getToUserId(), payment.getAmount());
        } catch (Exception e) {
            // 异常被捕获,事务不会回滚
            log.error("支付失败", e);
        }
    }
}

原因 :Spring默认只在抛出RuntimeExceptionError时才回滚事务。当异常被catch块捕获后,事务管理器无法感知异常的发生,所以不会触发回滚。

解决方案

java 复制代码
// 方案1:重新抛出异常
@Transactional
public void processPayment(Payment payment) {
    try {
        accountDao.deduct(payment.getUserId(), payment.getAmount());
        if (payment.getAmount().compareTo(new BigDecimal("10000")) > 0) {
            throw new RuntimeException("金额超限");
        }
        accountDao.credit(payment.getToUserId(), payment.getAmount());
    } catch (Exception e) {
        log.error("支付失败", e);
        throw e;  // 重新抛出异常,触发回滚
    }
}

// 方案2:指定回滚异常类型
@Transactional(rollbackFor = Exception.class)
public void processPayment(Payment payment) {
    try {
        accountDao.deduct(payment.getUserId(), payment.getAmount());
        if (payment.getAmount().compareTo(new BigDecimal("10000")) > 0) {
            throw new RuntimeException("金额超限");
        }
        accountDao.credit(payment.getToUserId(), payment.getAmount());
    } catch (Exception e) {
        log.error("支付失败", e);
        // 即使捕获异常,也会回滚
    }
}

6.6 异常类型不匹配

问题代码

java 复制代码
@Service
public class UserService {
    
    // 默认只回滚RuntimeException
    @Transactional
    public void updateUser(User user) throws Exception {
        userDao.update(user);
        // 抛出受检异常,默认不会回滚
        throw new Exception("用户更新失败");
    }
}

原因 :Spring默认只在抛出RuntimeException(非受检异常)和Error时回滚事务。对于受检异常(checked exception,如Exception、IOException等),默认不会触发回滚。

解决方案

java 复制代码
// 方案1:指定回滚异常类型
@Transactional(rollbackFor = Exception.class)
public void updateUser(User user) throws Exception {
    userDao.update(user);
    throw new Exception("用户更新失败");  // 现在会回滚
}

// 方案2:抛出RuntimeException
@Transactional
public void updateUser(User user) {
    userDao.update(user);
    throw new RuntimeException("用户更新失败");  // 默认会回滚
}

6.7 数据库引擎不支持事务

问题代码

java 复制代码
// MySQL表使用MyISAM引擎
@Transactional
public void saveUser(User user) {
    userDao.save(user);  // 事务不会生效
}

原因:事务的最终支持是由数据库提供的。如果数据库表使用的是不支持事务的存储引擎(如MySQL的MyISAM),那么即使Spring配置了事务,也无法实现事务的回滚功能。

解决方案:确保数据库表使用支持事务的存储引擎(如MySQL的InnoDB)。

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

6.8 事务传播机制设置不当

问题代码

java 复制代码
@Service
public class OrderService {
    
    @Autowired
    private PaymentService paymentService;
    
    @Transactional
    public void createOrder(Order order) {
        orderDao.save(order);
        // 即使这里抛出异常,paymentService也不会回滚
        paymentService.processPayment(order);
    }
}

@Service
public class PaymentService {
    
    // NOT_SUPPORTED传播机制,暂停当前事务
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void processPayment(Order order) {
        accountDao.deduct(order.getUserId(), order.getAmount());
        // 这里抛出异常,不会影响createOrder的事务
        if (order.getAmount().compareTo(new BigDecimal("10000")) > 0) {
            throw new RuntimeException("金额超限");
        }
    }
}

原因 :某些传播机制会导致事务行为不符合预期。如NOT_SUPPORTEDNEVERSUPPORTS(无事务时)等传播机制会导致方法在非事务环境下执行,事务自然失效。

解决方案:根据业务需求选择合适的事务传播机制。

java 复制代码
// 使用REQUIRED传播机制,确保加入当前事务
@Transactional(propagation = Propagation.REQUIRED)
public void processPayment(Order order) {
    accountDao.deduct(order.getUserId(), order.getAmount());
    // 现在抛出异常会触发回滚
    if (order.getAmount().compareTo(new BigDecimal("10000")) > 0) {
        throw new RuntimeException("金额超限");
    }
}

6.9 多线程调用

问题代码

java 复制代码
@Service
public class UserService {
    
    @Transactional
    public void batchSaveUsers(List<User> users) {
        // 创建新线程
        new Thread(() -> {
            // 在新线程中执行,事务失效
            for (User user : users) {
                userDao.save(user);
            }
        }).start();
    }
}

原因:Spring的事务是基于ThreadLocal实现的,事务上下文绑定在当前线程。当在新线程中执行数据库操作时,新线程无法获取到主线程的事务上下文,所以事务失效。

解决方案:避免在事务方法中创建新线程,如果必须使用多线程,需要在新线程中手动管理事务。

java 复制代码
// 方案1:不使用多线程
@Transactional
public void batchSaveUsers(List<User> users) {
    for (User user : users) {
        userDao.save(user);  // 在当前线程执行,事务生效
    }
}

// 方案2:使用编程式事务在新线程中管理事务
public void batchSaveUsers(List<User> users) {
    new Thread(() -> {
        // 在新线程中手动开启事务
        TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
        transactionTemplate.execute(status -> {
            for (User user : users) {
                userDao.save(user);
            }
            return null;
        });
    }).start();
}

6.10 事务管理器配置错误

问题代码

java 复制代码
@Configuration
public class TransactionConfig {
    
    // 事务管理器配置错误
    @Bean
    public PlatformTransactionManager transactionManager() {
        // 使用了错误的数据源
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(wrongDataSource);  // 错误的数据源
        return transactionManager;
    }
}

@Service
public class UserService {
    
    @Autowired
    private UserDao userDao;  // userDao使用的是正确的数据源
    
    @Transactional
    public void saveUser(User user) {
        userDao.save(user);  // 事务失效
    }
}

原因:如果事务管理器配置的数据源与实际使用的Dao层数据源不一致,事务管理器无法正确管理事务。

解决方案:确保事务管理器使用正确的数据源。

java 复制代码
@Configuration
public class TransactionConfig {
    
    @Autowired
    private DataSource dataSource;  // 正确的数据源
    
    @Bean
    public PlatformTransactionManager transactionManager() {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);  // 使用正确的数据源
        return transactionManager;
    }
}

6.11 类未被Spring管理

问题代码

java 复制代码
// 没有添加@Service注解
public class UserService {
    
    @Autowired
    private UserDao userDao;
    
    @Transactional
    public void saveUser(User user) {
        userDao.save(user);  // 事务失效
    }
}

// 或者手动创建对象
@Service
public class OrderController {
    
    public void createOrder() {
        // 手动创建对象,不是Spring管理的Bean
        UserService userService = new UserService();
        userService.saveUser(new User());  // 事务失效
    }
}

原因:Spring的事务是通过AOP代理实现的,只有被Spring容器管理的Bean才会被代理。如果类没有被Spring管理(没有添加@Service等注解,或者手动创建对象),Spring无法为其创建代理,事务失效。

解决方案:确保类被Spring容器管理。

java 复制代码
@Service  // 添加@Service注解
public class UserService {
    
    @Autowired
    private UserDao userDao;
    
    @Transactional
    public void saveUser(User user) {
        userDao.save(user);  // 事务生效
    }
}

// 或者通过@Autowired注入
@Service
public class OrderController {
    
    @Autowired
    private UserService userService;  // 注入Spring管理的Bean
    
    public void createOrder() {
        userService.saveUser(new User());  // 事务生效
    }
}

6.12 代理机制限制

问题代码

java 复制代码
// 使用JDK动态代理,但实现了接口
@Service
public class UserServiceImpl implements UserService {
    
    @Transactional
    @Override
    public void saveUser(User user) {
        userDao.save(user);
    }
}

// 或者使用了错误的代理设置
@Configuration
@EnableTransactionManagement(proxyTargetClass = false)  // 强制使用JDK动态代理
public class TransactionConfig {
    
    // ...
}

// 类没有实现接口
@Service
public class UserService {  // 没有实现接口
    
    @Transactional
    public void saveUser(User user) {
        userDao.save(user);  // 可能代理失败
    }
}

原因:Spring默认使用JDK动态代理(需要实现接口)或CGLIB代理(不需要接口)。如果代理机制配置不当,可能导致代理创建失败,事务失效。

解决方案

java 复制代码
// 方案1:使用CGLIB代理
@Configuration
@EnableTransactionManagement(proxyTargetClass = true)  // 强制使用CGLIB
public class TransactionConfig {
    
    // ...
}

// 方案2:确保接口实现正确
public interface UserService {
    void saveUser(User user);
}

@Service
public class UserServiceImpl implements UserService {
    
    @Transactional
    @Override
    public void saveUser(User user) {
        userDao.save(user);
    }
}

七、事务失效问题排查清单

当遇到事务失效问题时,可以按照以下清单逐一排查:

java 复制代码
// 事务失效排查清单
1. 检查方法是否为public
2. 检查方法是否被final修饰
3. 检查方法是否被static修饰
4. 检查是否存在同类自调用
5. 检查异常是否被正确抛出
6. 检查异常类型是否匹配
7. 检查数据库引擎是否支持事务
8. 检查事务传播机制设置
9. 检查是否使用了多线程
10. 检查事务管理器配置是否正确
11. 检查类是否被Spring管理
12. 检查代理机制配置是否正确

八、面试常考:核心要点总结

8.1 Spring事务核心问题

  1. Spring事务的本质:基于AOP和数据库事务的封装管理
  2. @Transactional工作原理:通过AOP代理,在方法执行前后开启/提交/回滚事务
  3. 事务失效的12种原因
    • 方法访问权限非public
    • 方法被final修饰
    • 方法被static修饰
    • 同一个类中的自调用
    • 异常被捕获未重新抛出
    • 异常类型不匹配
    • 数据库引擎不支持事务
    • 事务传播机制设置不当
    • 多线程调用
    • 事务管理器配置错误
    • 类未被Spring管理
    • 代理机制限制

8.2 事务传播行为记忆口诀

复制代码
REQUIRED: 有就加入,没有就创建
REQUIRES_NEW: 总是创建新的
SUPPORTS: 有就加入,没有就不需要
NOT_SUPPORTED: 总是非事务执行
MANDATORY: 必须有事务,否则报错
NEVER: 绝对不能有事务,否则报错
NESTED: 有就嵌套,没有就创建

8.3 最佳实践建议

  1. 类级别配置 :在Service类上添加@Transactional,方法级别根据需要覆盖
  2. 明确异常 :使用rollbackFor = Exception.class明确指定回滚异常类型
  3. 合理隔离:根据业务需求选择合适的隔离级别
  4. 避免长事务:长事务会占用数据库资源,影响系统性能
  5. 测试验证:重要业务逻辑需要测试事务的回滚和提交
  6. 方法设计:确保事务方法为public、非final、非static
  7. 避免自调用:同类方法调用需要通过代理对象进行
  8. 异常处理:不要在事务方法中吞掉异常,要么重新抛出,要么指定rollbackFor

8.4 高级面试题

Q1:Spring事务和编程式事务有什么区别?

A:声明式事务通过AOP实现,侵入性小,适合大多数场景;编程式事务需要手动管理事务,灵活性高但代码复杂,适用于需要细粒度控制的场景。

Q2:嵌套事务和加入现有事务有什么区别?

A:嵌套事务(NESTED)可以独立回滚,不影响外部事务;加入现有事务(REQUIRED)与外部事务是一个整体,回滚时一起回滚。

Q3:如何监控Spring事务的执行情况?

A:可以通过Spring的事务事件机制、日志配置、或者AOP切面来监控事务的开始、提交、回滚等事件。

Q4:为什么private方法不能使用@Transactional?

A:因为Spring的事务是基于AOP代理实现的,代理类需要重写目标方法。private方法无法被外部类访问,也就无法被重写,所以代理无法生成,事务自然失效。

Q5:在同一个Service中,方法A调用方法B,方法B有@Transactional注解,为什么事务会失效?

A :因为方法A调用方法B时,使用的是this引用,调用的是原始对象的方法,而不是经过代理增强的方法。Spring的AOP代理是通过代理对象来拦截方法调用的,内部调用绕过了代理,所以事务失效。

Q6:如何解决同一个Service中方法调用的事务失效问题?

A :可以通过注入自身(@Autowired private SelfService self;)然后通过self.methodB()调用,或者将方法B提取到另一个Service中,通过调用不同Service的方法来实现事务传播。

Q7:Spring事务的隔离级别有哪些?

A

  • DEFAULT:使用数据库默认隔离级别
  • READ_UNCOMMITTED:读未提交(可能脏读)
  • READ_COMMITTED:读已提交(避免脏读,可能不可重复读)
  • REPEATABLE_READ:可重复读(避免脏读、不可重复读,可能幻读)
  • SERIALIZABLE:串行化(最高隔离级别,避免所有并发问题)

Q8:什么是脏读、不可重复读、幻读?

A

  • 脏读:一个事务读取了另一个未提交事务的数据
  • 不可重复读:在同一个事务中,多次读取同一数据得到不同结果
  • 幻读:在同一个事务中,多次查询返回的结果集不同

总结:Spring事务管理是Java开发中的必备技能,理解其工作原理和失效场景对于构建可靠的企业级应用至关重要。掌握本文的12种事务失效场景,你就能在面试和实际开发中快速定位和解决事务问题!

最后提示:纸上得来终觉浅,绝知此事要躬行。建议读者在实际项目中多实践、多踩坑、多总结,才能真正掌握Spring事务的精髓!

相关推荐
小光学长5 小时前
基于ssm的校园约自习网站23i21xj4(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
java·数据库·spring
振鹏Dong6 小时前
ReActAgent 源码深度拆解:从调用入口到 ReAct-Loop,读懂智能体 “推理 - 行动” 范式
java·人工智能·spring·ai
BD_Marathon6 小时前
原型模式——Spring源码分析
java·spring·原型模式
m***78747 小时前
开源模型应用落地-工具使用篇-Spring AI-高阶用法(九)
人工智能·spring·开源
❀͜͡傀儡师7 小时前
SpringBoot 4.0新特性Resilience重试机制和并发限制
java·spring boot·spring
银发控、7 小时前
Builder Pattern
spring boot·spring·建造者模式
on the way 1238 小时前
day09 - Spring启动
java·后端·spring
yixin1238 小时前
Spring 多实例注入
java·后端·spring
zsyf19878 小时前
spring security 超详细使用教程(接入springboot、前后端分离)
java·spring boot·spring