Skip to content

Spring 编程式事务管理深度解析 🎯

前言:为什么需要编程式事务管理?

在 Spring 的世界里,我们通常使用 @Transactional 注解来处理事务,这种方式简单优雅。但有时候,我们需要更精细的控制——比如在一个方法中需要多个不同配置的事务,或者需要根据运行时条件动态决定事务行为。这时,编程式事务管理就派上用场了!

NOTE

编程式事务管理让你完全掌控事务的生命周期,虽然代码会稍微复杂一些,但换来的是最大的灵活性。

核心概念:Spring 事务管理的两种编程式方式

Spring 提供了两种主要的编程式事务管理方式:

TIP

Spring 团队推荐:对于传统的命令式代码使用 TransactionTemplate,对于响应式代码使用 TransactionalOperator

方式一:使用 TransactionTemplate ⭐

基本原理

TransactionTemplate 采用了模板方法模式,就像 JdbcTemplate 一样。它帮我们处理了事务资源的获取和释放,我们只需要专注于业务逻辑。

核心使用方式

kotlin
@Service
class UserService(
    private val userRepository: UserRepository,
    transactionManager: PlatformTransactionManager
) {
    // 单例 TransactionTemplate,线程安全
    private val transactionTemplate = TransactionTemplate(transactionManager)
    
    fun transferMoney(fromUserId: Long, toUserId: Long, amount: BigDecimal): String {
        return transactionTemplate.execute { status ->
            try {
                // 业务逻辑:转账操作
                val fromUser = userRepository.findById(fromUserId) 
                    ?: throw IllegalArgumentException("转出用户不存在")
                
                val toUser = userRepository.findById(toUserId) 
                    ?: throw IllegalArgumentException("转入用户不存在")
                
                if (fromUser.balance < amount) {
                    throw IllegalStateException("余额不足") 
                }
                
                // 执行转账
                fromUser.balance -= amount 
                toUser.balance += amount 
                
                userRepository.save(fromUser)
                userRepository.save(toUser)
                
                "转账成功:${amount}元" // 返回结果
                
            } catch (e: Exception) {
                status.setRollbackOnly() 
                throw e
            }
        } ?: "转账失败"
    }
}
kotlin
fun updateUserBatch(userIds: List<Long>) {
    transactionTemplate.execute(object : TransactionCallbackWithoutResult() {
        override fun doInTransactionWithoutResult(status: TransactionStatus) {
            try {
                userIds.forEach { userId ->
                    val user = userRepository.findById(userId) 
                    user?.let {
                        it.lastUpdateTime = LocalDateTime.now()
                        userRepository.save(it) 
                    }
                }
            } catch (e: Exception) {
                status.setRollbackOnly() 
                throw e
            }
        }
    })
}

自定义事务配置

有时候我们需要为特定的业务场景配置不同的事务参数:

kotlin
@Service
class ReportService(transactionManager: PlatformTransactionManager) {
    
    // 只读事务模板 - 用于复杂查询
    private val readOnlyTemplate = TransactionTemplate(transactionManager).apply {
        isReadOnly = true
        isolationLevel = TransactionDefinition.ISOLATION_READ_COMMITTED
        timeout = 60 // 60秒超时
    }
    
    // 写事务模板 - 用于数据修改
    private val writeTemplate = TransactionTemplate(transactionManager).apply {
        isolationLevel = TransactionDefinition.ISOLATION_REPEATABLE_READ 
        timeout = 30 // 30秒超时
        propagationBehavior = TransactionDefinition.PROPAGATION_REQUIRED
    }
    
    fun generateComplexReport(): ReportData {
        return readOnlyTemplate.execute { 
            // 复杂的只读查询操作
            val userData = userRepository.findAllWithDetails()
            val orderData = orderRepository.findAllWithItems()
            
            ReportData(userData, orderData)
        } ?: throw RuntimeException("报表生成失败")
    }
    
    fun updateReportCache(reportData: ReportData) {
        writeTemplate.execute(object : TransactionCallbackWithoutResult() { 
            override fun doInTransactionWithoutResult(status: TransactionStatus) {
                reportCacheRepository.deleteAll()
                reportCacheRepository.saveAll(reportData.toCacheEntities())
            }
        })
    }
}

IMPORTANT

TransactionTemplate 实例是线程安全的,可以在多个方法间共享。但如果需要不同的事务配置,就需要创建不同的实例。

方式二:使用 TransactionalOperator(响应式) 🚀

对于使用 WebFlux 的响应式应用,我们需要使用 TransactionalOperator

kotlin
@Service
class ReactiveUserService(
    private val userRepository: ReactiveUserRepository,
    transactionManager: ReactiveTransactionManager
) {
    private val transactionalOperator = TransactionalOperator.create(transactionManager)
    
    suspend fun transferMoneyReactive(
        fromUserId: Long, 
        toUserId: Long, 
        amount: BigDecimal
    ): String {
        return transactionalOperator.executeAndAwait { 
            val fromUser = userRepository.findById(fromUserId).awaitSingle()
            val toUser = userRepository.findById(toUserId).awaitSingle()
            
            if (fromUser.balance < amount) {
                throw IllegalStateException("余额不足")
            }
            
            fromUser.balance -= amount
            toUser.balance += amount
            
            userRepository.save(fromUser).awaitSingle() 
            userRepository.save(toUser).awaitSingle() 
            
            "转账成功:${amount}元"
        }
    }
    
    // 使用 Reactor 操作符风格
    fun transferMoneyFlux(fromUserId: Long, toUserId: Long, amount: BigDecimal): Mono<String> {
        val transferMono = userRepository.findById(fromUserId)
            .zipWith(userRepository.findById(toUserId))
            .flatMap { tuple ->
                val (fromUser, toUser) = tuple
                
                if (fromUser.balance < amount) {
                    return@flatMap Mono.error<String>(IllegalStateException("余额不足"))
                }
                
                fromUser.balance -= amount
                toUser.balance += amount
                
                userRepository.save(fromUser)
                    .then(userRepository.save(toUser))
                    .thenReturn("转账成功:${amount}元")
            }
        
        return transferMono.`as`(transactionalOperator::transactional) 
    }
}

WARNING

在响应式编程中,取消信号会导致事务回滚。确保完全消费 Flux 或其他多值 Publisher 的输出,以允许事务完成。

方式三:直接使用 TransactionManager 🔧

当你需要最大程度的控制时,可以直接使用事务管理器:

kotlin
@Service
class AdvancedUserService(
    private val txManager: PlatformTransactionManager,
    private val userRepository: UserRepository
) {
    
    fun complexBusinessOperation(): String {
        val def = DefaultTransactionDefinition().apply {
            name = "ComplexBusinessTx"
            propagationBehavior = TransactionDefinition.PROPAGATION_REQUIRED
            isolationLevel = TransactionDefinition.ISOLATION_READ_COMMITTED
            timeout = 30
        }
        
        val status = txManager.getTransaction(def) 
        
        try {
            // 第一阶段:数据验证
            val users = userRepository.findAllActiveUsers()
            if (users.isEmpty()) {
                throw IllegalStateException("没有活跃用户")
            }
            
            // 第二阶段:业务处理
            users.forEach { user ->
                user.lastLoginTime = LocalDateTime.now()
                userRepository.save(user)
            }
            
            // 第三阶段:提交事务
            txManager.commit(status) 
            return "操作成功,处理了 ${users.size} 个用户"
            
        } catch (ex: Exception) {
            txManager.rollback(status) 
            throw ex
        }
    }
}
kotlin
@Service
class ReactiveAdvancedService(
    private val txManager: ReactiveTransactionManager,
    private val userRepository: ReactiveUserRepository
) {
    
    fun complexReactiveOperation(): Mono<String> {
        val def = DefaultTransactionDefinition().apply {
            name = "ComplexReactiveTx"
            propagationBehavior = TransactionDefinition.PROPAGATION_REQUIRED
        }
        
        return txManager.getReactiveTransaction(def) 
            .flatMap { status ->
                val businessLogic = userRepository.findAllActiveUsers()
                    .collectList()
                    .flatMap { users ->
                        if (users.isEmpty()) {
                            Mono.error(IllegalStateException("没有活跃用户"))
                        } else {
                            val updatedUsers = users.map { user ->
                                user.lastLoginTime = LocalDateTime.now()
                                user
                            }
                            userRepository.saveAll(updatedUsers)
                                .collectList()
                                .map { "操作成功,处理了 ${it.size} 个用户" }
                        }
                    }
                
                businessLogic
                    .flatMap { result ->
                        txManager.commit(status).thenReturn(result) 
                    }
                    .onErrorResume { ex ->
                        txManager.rollback(status) 
                            .then(Mono.error(ex))
                    }
            }
    }
}

实际应用场景对比 📊

让我们看看在实际业务中,不同方式的适用场景:

kotlin
// 使用 TransactionTemplate 处理批量操作
@Service
class BatchProcessService(
    private val transactionTemplate: TransactionTemplate,
    private val orderRepository: OrderRepository
) {
    
    fun processBatchOrders(orderIds: List<Long>): BatchResult {
        return transactionTemplate.execute { status ->
            val successIds = mutableListOf<Long>()
            val failedIds = mutableListOf<Long>()
            
            orderIds.forEach { orderId ->
                try {
                    val order = orderRepository.findById(orderId)
                    order?.let {
                        it.status = OrderStatus.PROCESSED 
                        it.processedAt = LocalDateTime.now()
                        orderRepository.save(it)
                        successIds.add(orderId)
                    }
                } catch (e: Exception) {
                    failedIds.add(orderId)
                    // 注意:这里不抛出异常,继续处理其他订单
                }
            }
            
            if (failedIds.isNotEmpty() && successIds.isEmpty()) {
                status.setRollbackOnly() 
            }
            
            BatchResult(successIds, failedIds)
        } ?: BatchResult(emptyList(), orderIds)
    }
}
kotlin
// 根据条件决定是否开启事务
@Service
class ConditionalTransactionService(
    private val txManager: PlatformTransactionManager,
    private val dataRepository: DataRepository
) {
    
    fun processData(data: DataEntity, useTransaction: Boolean): String {
        if (!useTransaction) {
            // 不使用事务的简单处理
            return dataRepository.save(data).let { "数据保存成功" }
        }
        
        // 使用事务的复杂处理
        val def = DefaultTransactionDefinition().apply {
            isolationLevel = when (data.priority) { 
                Priority.HIGH -> TransactionDefinition.ISOLATION_SERIALIZABLE
                Priority.MEDIUM -> TransactionDefinition.ISOLATION_REPEATABLE_READ
                else -> TransactionDefinition.ISOLATION_READ_COMMITTED
            }
        }
        
        val status = txManager.getTransaction(def)
        
        try {
            // 复杂的业务逻辑
            val validatedData = validateData(data)
            val enrichedData = enrichData(validatedData)
            val savedData = dataRepository.save(enrichedData)
            
            txManager.commit(status)
            return "事务处理成功:${savedData.id}"
            
        } catch (ex: Exception) {
            txManager.rollback(status)
            throw ex
        }
    }
}

最佳实践与注意事项 💡

1. 选择合适的方式

2. 异常处理策略

CAUTION

编程式事务管理中,你需要手动处理异常和回滚。不像声明式事务会自动回滚运行时异常。

kotlin
// ❌ 错误的异常处理
transactionTemplate.execute { status ->
    try {
        businessLogic()
    } catch (e: Exception) {
        // 忘记调用 setRollbackOnly()
        return@execute "处理失败"
    }
}

// ✅ 正确的异常处理
transactionTemplate.execute { status ->
    try {
        businessLogic()
        "处理成功"
    } catch (e: Exception) {
        status.setRollbackOnly() 
        throw e // 重新抛出异常
    }
}

3. 性能优化建议

性能优化要点

  • 复用 TransactionTemplate 实例:它们是线程安全的
  • 合理设置超时时间:避免长时间锁定资源
  • 选择合适的隔离级别:平衡一致性和性能
  • 批量操作优化:减少事务开销

总结:编程式 vs 声明式事务管理 🎯

特性编程式事务管理声明式事务管理
灵活性⭐⭐⭐⭐⭐ 完全控制⭐⭐⭐ 配置驱动
简洁性⭐⭐ 代码较多⭐⭐⭐⭐⭐ 注解即可
性能⭐⭐⭐⭐ 精确控制⭐⭐⭐⭐ AOP 开销
维护性⭐⭐⭐ 需要手动管理⭐⭐⭐⭐⭐ 框架管理
适用场景复杂业务逻辑常规 CRUD 操作

最终建议

  • 日常开发:优先使用 @Transactional 声明式事务
  • 复杂场景:使用 TransactionTemplateTransactionalOperator
  • 极致控制:直接使用 TransactionManager

编程式事务管理虽然代码量更多,但它给了你完全的控制权。在需要精细化事务管理的场景下,它是不可替代的工具! 🚀