声明式事务

声明式事务:详解与系统学习指南

📚 核心面试题及详解

1. 什么是声明式事务?与编程式事务的区别是什么?

参考答案

声明式事务是通过配置或注解 的方式声明事务边界,由框架自动管理事务的开启、提交和回滚。编程式事务则是手动编写代码控制事务。

java 复制代码
// 声明式事务(Spring示例)
@Service
@Transactional
public class UserService {
    public void transferMoney(Account from, Account to, BigDecimal amount) {
        // 业务逻辑,事务由框架自动管理
        from.debit(amount);
        to.credit(amount);
    }
}

// 编程式事务
@Service
public class UserService {
    @Autowired
    private PlatformTransactionManager transactionManager;
    
    public void transferMoney(Account from, Account to, BigDecimal amount) {
        TransactionStatus status = transactionManager.getTransaction(
            new DefaultTransactionDefinition());
        try {
            from.debit(amount);
            to.credit(amount);
            transactionManager.commit(status);
        } catch (Exception e) {
            transactionManager.rollback(status);
            throw e;
        }
    }
}

对比总结

方面 声明式事务 编程式事务
实现方式 配置/注解 手动编码
代码侵入性
可维护性 高(业务与事务分离)
灵活性 相对较低 高(精确控制)
适用场景 大多数业务场景 复杂事务控制

2. Spring声明式事务的实现原理是什么?

核心答案

Spring通过AOP(面向切面编程)动态代理实现声明式事务。

java 复制代码
// 简化版实现原理示意
public class TransactionInterceptor implements MethodInterceptor {
    @Autowired
    private PlatformTransactionManager transactionManager;
    
    public Object invoke(MethodInvocation invocation) throws Throwable {
        // 1. 获取事务属性
        TransactionAttribute txAttr = getTransactionAttribute(invocation.getMethod());
        
        // 2. 创建事务
        TransactionStatus status = transactionManager.getTransaction(txAttr);
        
        try {
            // 3. 执行业务方法(通过反射调用目标方法)
            Object result = invocation.proceed();
            
            // 4. 提交事务
            transactionManager.commit(status);
            return result;
        } catch (Exception ex) {
            // 5. 处理回滚
            completeTransactionAfterThrowing(status, txAttr, ex);
            throw ex;
        }
    }
}

关键组件

  • @Transactional注解:标记事务边界
  • TransactionInterceptor:事务拦截器(AOP通知)
  • PlatformTransactionManager:事务管理器抽象
  • TransactionAttributeSource:事务属性源

3. @Transactional注解有哪些重要属性?

java 复制代码
public @interface Transactional {
    // 1. 传播行为(最重要的属性)
    Propagation propagation() default Propagation.REQUIRED;
    
    // 2. 隔离级别
    Isolation isolation() default Isolation.DEFAULT;
    
    // 3. 超时时间(秒)
    int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
    
    // 4. 是否只读
    boolean readOnly() default false;
    
    // 5. 回滚规则
    Class<? extends Throwable>[] rollbackFor() default {};
    String[] rollbackForClassName() default {};
    Class<? extends Throwable>[] noRollbackFor() default {};
    String[] noRollbackForClassName() default {};
}

4. Spring事务传播行为有哪些?请详细解释

七种传播行为(按重要性排序):

java 复制代码
public enum Propagation {
    // 1. REQUIRED(默认):当前有事务则加入,没有则新建
    REQUIRED,
    
    // 2. REQUIRES_NEW:新建事务,挂起当前事务(独立提交/回滚)
    REQUIRES_NEW,
    
    // 3. NESTED:嵌套事务,使用保存点(Savepoint)
    //    外部事务回滚会导致嵌套事务回滚
    //    嵌套事务回滚不会影响外部事务(除非后续操作失败)
    NESTED,
    
    // 4. SUPPORTS:有事务则加入,没有则以非事务方式执行
    SUPPORTS,
    
    // 5. NOT_SUPPORTED:以非事务方式执行,挂起当前事务
    NOT_SUPPORTED,
    
    // 6. MANDATORY:必须有事务,否则抛异常
    MANDATORY,
    
    // 7. NEVER:必须没有事务,否则抛异常
    NEVER
}

经典场景示例

java 复制代码
@Service
public class OrderService {
    @Transactional(propagation = Propagation.REQUIRED)
    public void placeOrder(Order order) {
        // 主业务逻辑
        orderDao.save(order);
        
        // 记录日志(独立事务,即使日志失败也不影响主事务)
        try {
            logService.addLog("Order placed: " + order.getId());
        } catch (Exception e) {
            // 日志异常被捕获,不影响主事务
        }
    }
}

@Service
public class LogService {
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void addLog(String message) {
        // 独立事务执行
        logDao.save(new Log(message));
    }
}

5. 事务隔离级别有哪些?Spring如何实现?

四种隔离级别

java 复制代码
public enum Isolation {
    DEFAULT(-1),           // 使用数据库默认
    READ_UNCOMMITTED(1),   // 读未提交(可能脏读)
    READ_COMMITTED(2),     // 读已提交(Oracle默认)
    REPEATABLE_READ(4),    // 可重复读(MySQL默认)
    SERIALIZABLE(8);       // 串行化
}

问题与解决方案

隔离级别 脏读 不可重复读 幻读 性能
READ_UNCOMMITTED ✅ 可能 ✅ 可能 ✅ 可能 ⭐⭐⭐⭐⭐
READ_COMMITTED ❌ 避免 ✅ 可能 ✅ 可能 ⭐⭐⭐⭐
REPEATABLE_READ ❌ 避免 ❌ 避免 ✅ 可能 ⭐⭐⭐
SERIALIZABLE ❌ 避免 ❌ 避免 ❌ 避免

6. Spring事务在什么情况下会失效?

常见失效场景

java 复制代码
@Service
public class UserService {
    // 场景1:自调用(同一个类内的方法调用)
    public void methodA() {
        methodB();  // ❌ 事务失效!未通过代理调用
    }
    
    @Transactional
    public void methodB() {
        // ...
    }
    
    // 场景2:异常被捕获
    @Transactional
    public void methodC() {
        try {
            // 业务逻辑
            throw new RuntimeException("业务异常");
        } catch (Exception e) {
            // ❌ 异常被捕获,事务不会回滚
        }
    }
    
    // 场景3:非public方法
    @Transactional
    private void methodD() {  // ❌ 事务失效
        // ...
    }
    
    // 场景4:异常类型不匹配
    @Transactional(rollbackFor = RuntimeException.class)
    public void methodE() throws Exception {
        throw new Exception();  // ❌ Exception不是RuntimeException
    }
}

🔍 深入学习路径

第一阶段:基础概念(1-2天)

  1. ACID原则理解

    • Atomicity(原子性):要么全部成功,要么全部失败
    • Consistency(一致性):数据完整性约束
    • Isolation(隔离性):并发事务互不干扰
    • Durability(持久性):提交后永久保存
  2. 本地事务 vs 分布式事务

    • 本地事务:单个数据库连接
    • 分布式事务:多个数据源(XA协议、Seata等)

第二阶段:Spring事务实现(3-5天)

  1. 核心源码阅读路线

    复制代码
    @Transactional注解
        ↓
    TransactionInterceptor(事务拦截器)
        ↓
    PlatformTransactionManager(事务管理器)
        ↓
    AbstractPlatformTransactionManager(抽象实现)
        ↓
    DataSourceTransactionManager(数据源事务管理)
        ↓
    TransactionSynchronizationManager(事务同步管理)
  2. 代理模式理解

    java 复制代码
    // JDK动态代理(接口代理)
    public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
        public Object invoke(Object proxy, Method method, Object[] args) {
            // 事务拦截逻辑
        }
    }
    
    // CGLIB代理(类代理)
    public class CglibAopProxy implements AopProxy {
        public Object intercept(Object proxy, Method method, Object[] args, 
                                MethodProxy methodProxy) {
            // 事务拦截逻辑
        }
    }

第三阶段:高级特性与实践(5-7天)

  1. 事务同步机制

    java 复制代码
    @Service
    public class OrderService {
        @Transactional
        public void createOrder(Order order) {
            orderDao.save(order);
            
            // 事务同步:事务提交后执行
            TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronizationAdapter() {
                    @Override
                    public void afterCommit() {
                        // 发送消息、清理缓存等
                        sendOrderCreatedEvent(order);
                    }
                }
            );
        }
    }
  2. 多数据源事务管理

    java 复制代码
    @Configuration
    public class TransactionConfig {
        @Bean
        @Primary
        public PlatformTransactionManager primaryTxManager(DataSource dataSource) {
            return new DataSourceTransactionManager(dataSource);
        }
        
        @Bean
        public PlatformTransactionManager secondaryTxManager(
            @Qualifier("secondaryDataSource") DataSource dataSource) {
            return new DataSourceTransactionManager(dataSource);
        }
    }
    
    @Service
    public class MultiDataSourceService {
        @Transactional("primaryTxManager")
        public void methodInPrimary() { /* ... */ }
        
        @Transactional("secondaryTxManager")
        public void methodInSecondary() { /* ... */ }
        
        // 注意:跨数据源需要分布式事务解决方案
    }

第四阶段:性能优化与监控(2-3天)

  1. 事务监控指标

    java 复制代码
    // 使用Micrometer监控事务
    @Component
    public class TransactionMetrics {
        private final MeterRegistry meterRegistry;
        
        public void recordTransaction(String method, long duration, boolean success) {
            Counter.builder("transactions.total")
                .tag("method", method)
                .tag("success", String.valueOf(success))
                .register(meterRegistry)
                .increment();
            
            Timer.builder("transactions.duration")
                .tag("method", method)
                .register(meterRegistry)
                .record(duration, TimeUnit.MILLISECONDS);
        }
    }
  2. 常见优化策略

    • 合理设置事务超时时间
    • 只读事务优化
    • 批量操作的事务拆分
    • 避免大事务(长事务)

🎯 高频面试题补充

Q1:Spring如何选择使用JDK代理还是CGLIB代理?

:Spring Boot 2.x默认使用CGLIB代理。可通过配置修改:

properties 复制代码
# 使用JDK动态代理(基于接口)
spring.aop.proxy-target-class=false

# 使用CGLIB代理(基于类)【默认】
spring.aop.proxy-target-class=true

Q2:@Transactional和synchronized能保证线程安全吗?

:不能!这是常见误解:

java 复制代码
@Service
public class AccountService {
    private final Map<Long, BigDecimal> cache = new ConcurrentHashMap<>();
    
    @Transactional
    public synchronized void transfer(Long fromId, Long toId, BigDecimal amount) {
        // ❌ 仍然可能有问题!
        // 事务在方法结束后才提交,其他线程可能读到未提交的数据
        Account from = accountDao.findById(fromId);
        Account to = accountDao.findById(toId);
        // ...
    }
}

Q3:如何调试事务问题?

:开启Spring事务调试日志:

properties 复制代码
logging.level.org.springframework.transaction.interceptor=TRACE
logging.level.org.springframework.jdbc.datasource.DataSourceTransactionManager=DEBUG

📊 学习资源推荐

官方文档

  1. Spring Framework Transactions
  2. Spring Boot Transaction Management

源码学习

bash 复制代码
# 关键源码位置
spring-tx/
  ├── spring-tx/src/main/java/org/springframework/transaction
  │   ├── annotation/Transactional.java      # 注解定义
  │   ├── interceptor/TransactionInterceptor.java  # 拦截器
  │   └── support/AbstractPlatformTransactionManager.java
  └── spring-jdbc/src/main/java/org/springframework/jdbc/datasource
        └── DataSourceTransactionManager.java

实践项目建议

创建一个"银行转账系统",实现:

  1. 基本的事务管理
  2. 多种传播行为测试
  3. 事务失效场景复现
  4. 事务监控与报警

💡 面试技巧

  1. 回答要有层次:先讲概念,再讲实现,最后举例
  2. 结合项目经验:不要只背理论,要讲实际应用场景
  3. 诚实对待不懂的问题:可以坦率说"这个我不太熟悉,但我理解的是..."
  4. 主动展示深度:如果面试官问基础问题,可以适当延伸到高级话题

声明式事务是Spring框架的核心特性之一,理解其原理不仅能应对面试,更能提升日常开发中的问题排查能力和架构设计水平。建议通过"理论→源码→实践→优化"的路径系统学习。

相关推荐
_OP_CHEN3 小时前
【从零开始的Qt开发指南】(九)Qt 常用控件之显示类控件(下):ProgressBar 与 CalendarWidget 实战进阶
开发语言·c++·qt·gui·前端开发·图形化界面开发·qt常用控件
oioihoii3 小时前
VS Code终端从入门到精通完全指南
开发语言
武藤一雄3 小时前
C#:深入浅出委托(Delegate/Func/Action/Predicate)
开发语言·后端·microsoft·微软·c#·.net
妮妮喔妮3 小时前
Redis Cluster故障处理机制
java·数据库·redis
lang201509283 小时前
Sentinel预热限流:WarmUpController原理详解
java·spring·sentinel
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ3 小时前
SSE技术详解及应用场景
java
2501_941982053 小时前
RPA 赋能企业微信外部群:多群同步操作的技术实现
java·开发语言
Seven973 小时前
剑指offer-49、把字符串转换成整数
java
编程修仙3 小时前
第六篇 HttpServletRequest对象
java·spring boot·后端