Spring/SpringBoot中的声明式事务和编程式事务源码、区别、优缺点、适用场景、实战( 二 )

3、编程式事务源码编程式事务主要下面的代码:
public class TransactionTemplate extends DefaultTransactionDefinitionimplements TransactionOperations, InitializingBean{}TransactionTemplate UML图:

Spring/SpringBoot中的声明式事务和编程式事务源码、区别、优缺点、适用场景、实战

文章插图
TransactionTemplate类的execute()方法封装了事务的具体实现 , 通过调用TransactionCallback对象的doInTransaction()方法来执行业务逻辑并管理事务 。在具体实现中 , TransactionTemplate类会自动控制事务的提交和回滚 , 并将异常抛出给上层调用者进行处理 。
 @Override@Nullablepublic <T> T execute(TransactionCallback<T> action) throws TransactionException {Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);}else {TransactionStatus status = this.transactionManager.getTransaction(this);T result;try {result = action.doInTransaction(status);}catch (RuntimeException | Error ex) {// Transactional code threw Application exception -> rollbackrollbackOnException(status, ex);throw ex;}catch (Throwable ex) {// Transactional code threw unexpected exception -> rollbackrollbackOnException(status, ex);throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");}this.transactionManager.commit(status);return result;}}三、两者区别上面说了源码里的大体实现 , 下面我们来介绍一下两者区别:
  1. 技术实现方式:声明式事务是通过AOP技术来实现的 , 而编程式事务是通过编写具体的代码来实现的 。
  2. 代码耦合度:声明式事务可以将事务处理逻辑从业务代码中分离出来 , 从而降低代码的耦合度 。而编程式事务需要在业务代码中显式地调用事务管理代码 , 因此会增加代码的耦合度 。
  3. 难易程度:声明式事务相对来说比较容易上手 , 开发人员只需要学习注解或XML配置即可 。而编程式事务需要开发人员理解事务管理的底层机制 , 并编写具体的代码 。
  4. 性能影响:由于声明式事务是由容器来处理的 , 所以在一些场景下可能会对性能产生影响 , 大事务会有很多问题(下面在说一下大事务出现的问题) 。而编程式事务由于直接调用事务管理API , 相对来说会有更好的性能表现 。
总体而言 , 声明式事务和编程式事务都有各自的优缺点 , 开发人员需要根据具体需求选择适合的方式来控制事务 。
补充:
大事务时间过长可能会导致以下问题:
数据库锁定:当事务涉及到大量的数据操作时 , 事务可能会占用数据库资源并长时间锁定相关数据 。这可能会导致其他事务无法访问或修改这些数据 , 从而降低系统的并发性能和吞吐量 。
资源耗尽:长时间运行的事务需要占用更多的系统资源 , 如内存和CPU等 。如果系统资源不足 , 可能会导致系统出现延迟、死锁等问题 , 甚至导致系统崩溃 。
事务失败概率增加:当事务时间过长时 , 事务执行期间可能会发生各种错误 , 如网络故障、硬件故障、操作系统问题等 。此时 , 事务可能无法成功提交 , 导致数据丢失或数据不一致 。
应用程序超时:应用程序通常会为每个事务设置一个超时时间 , 以避免事务持续时间过长 。如果事务持续时间超过设定的超时时间 , 则应用程序可能会因为等待事务完成而阻塞 , 最终导致应用程序崩溃或超时 。
回滚时间增加:如果事务失败需要回滚 , 长时间运行的事务将需要更长的时间来进行回滚操作 。这可能会导致数据不一致或丢失 , 并增加数据库维护的工作量 。因此 , 开发人员应该尽量避免事务时间过长 , 合理地设置事务范围、优化事务操作方式以及减少数据访问次数等措施 , 以提高系统的并发性能和吞吐量 。
方案:大事务可以拆分小的事务 , 一下查询方面的可以提取出来 , 操作数据库的抽离出来专门加上事务 。也可以使用CompletableFuture组合式异步编排来解决大事务的问题!


推荐阅读