Spring事务专题(四)Spring中事务的使用、抽象机制及模拟Spring事务实现(2)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: Spring事务专题(四)Spring中事务的使用、抽象机制及模拟Spring事务实现(2)

Spring对事务的抽象


Spring事务抽象的关键就是事务策略的概念,事务策略是通过TransactionManager接口定义的。TransactionManager本身只是一个标记接口,它有两个直接子接口


1.ReactiveTransactionManager,这个接口主要用于在响应式编程模型下,不是我们要讨论的重点

2.PlatformTransactionManager,命令式编程模型下我们使用这个接口。

关于响应式跟命令式编程都可以单独写一篇文章了,本文重点不是讨论这两种编程模型,可以认为平常我们使用的都是命令式编程


PlatformTransactionManager


PlatformTransactionManager接口定义

public interface PlatformTransactionManager extends TransactionManager {
  // 开启事务
    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
    // 提交事务
    void commit(TransactionStatus status) throws TransactionException;
    // 回滚事务
    void rollback(TransactionStatus status) throws TransactionException;
}

PlatformTransactionManager是命令式编程模型下Spring事务机制的中心接口,定义了完成一个事务必须的三个步骤,也就是说定义了事务实现的规范


  • 开启事务
  • 提交事务
  • 回滚事务

通常来说,我们不会直接实现这个接口,而是通过继承AbstractPlatformTransactionManager,这个类是一个抽象类,主要用作事务管理的模板,这个抽象类已经实现了事务的传播行为以及跟事务相关的同步管理。


回头看接口中定义的三个方法,首先是开启事务的方法,从方法签名上来看,其作用就是通过一个TransactionDefinition来获取一个TransactionStatus类型的对象。为了更好的理解Spring中事务的抽象我们有必要了解下这两个接口


TransactionDefinition


接口定义如下:

public interface TransactionDefinition {
    // 定义了7中事务的传播机制
  int PROPAGATION_REQUIRED = 0;
  int PROPAGATION_SUPPORTS = 1;
  int PROPAGATION_MANDATORY = 2;
  int PROPAGATION_REQUIRES_NEW = 3;
  int PROPAGATION_NOT_SUPPORTED = 4;
  int PROPAGATION_NEVER = 5;
  int PROPAGATION_NESTED = 6;
    // 4种隔离级别,-1代表的是使用数据库默认的隔离级别
    // 比如在MySQL下,使用的就是ISOLATION_REPEATABLE_READ(可重复读)
  int ISOLATION_DEFAULT = -1;
  int ISOLATION_READ_UNCOMMITTED = 1;  
  int ISOLATION_READ_COMMITTED = 2; 
  int ISOLATION_REPEATABLE_READ = 4; 
  int ISOLATION_SERIALIZABLE = 8;  
    // 事务的超时时间,默认不限制时间
  int TIMEOUT_DEFAULT = -1;
    // 提供了对上面三个属性的get方法
  default int getPropagationBehavior() {
    return PROPAGATION_REQUIRED;
  }
  default int getIsolationLevel() {
    return ISOLATION_DEFAULT;
  }
  default int getTimeout() {
    return TIMEOUT_DEFAULT;
  }
    // 事务是否是只读的,默认不是
  default boolean isReadOnly() {
    return false;
  }
    // 事务的名称
  @Nullable
  default String getName() {
    return null;
  }
    // 返回一个只读的TransactionDefinition
    // 只对属性提供了getter方法,所有属性都是接口中定义的默认值
  static TransactionDefinition withDefaults() {
    return StaticTransactionDefinition.INSTANCE;
  }
}

从这个接口的名字上我们也能知道,它的主要完成了对事务定义的抽象,这些定义有些是数据库层面本身就有的,例如隔离级别、是否只读、超时时间、名称。也有些是Spring赋予的,例如事务的传播机制。Spring中一共定义了7种事务的传播机制


  • TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
  • TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
  • TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
  • TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。


关于事务的传播在源码分析的文章中我会重点介绍,现在大家留个印象即可。

我们在使用申明式事务的时候,会通过@Transactional这个注解去申明某个方法需要进行事务管理,在@Transactional中可以定义事务的属性,这些属性实际上就会被封装到一个TransactionDefinition中,当然封装的时候肯定不是直接使用的接口,而是这个接口的一个实现类RuleBasedTransactionAttribute。RuleBasedTransactionAttribute,该类的继承关系如下:

aHR0cHM6Ly9naXRlZS5jb20vd3hfY2MzNDdiZTY5Ni9ibG9nSW1hZ2UvcmF3L21hc3Rlci9SdWxlQmFzZWRUcmFuc2FjdGlvbkF0dHJpYnV0ZS5wbmc (1).png

DefaultTransactionDefinition,实现了TransactionDefinition,并为其中的定义的属性提供了默认值

// 默认的传播机制为required,没有事务新建一个事务
// 有事务的话加入当前事务
private int propagationBehavior = PROPAGATION_REQUIRED;
// 隔离级别跟数据库默认的隔离级别一直
private int isolationLevel = ISOLATION_DEFAULT;
// 默认为-1,不设置超时时间
private int timeout = TIMEOUT_DEFAULT;
// 默认不是只读的
private boolean readOnly = false;

TransactionAttribute,扩展了``DefaultTransactionDefinition`,新增了两个事务的属性

// 用于指定事务使用的事务管理器的名称
String getQualifier();
// 指定在出现哪种异常时才进行回滚
boolean rollbackOn(Throwable ex);

DefaultTransactionAttribute,继承了DefaultTransactionDefinition,同时实现了TransactionAttribute接口,定义了默认的回滚异常

// 抛出RuntimeException/Error才进行回滚
public boolean rollbackOn(Throwable ex) {
    return (ex instanceof RuntimeException || ex instanceof Error);
}

RuleBasedTransactionAttribute,@Transactional注解的rollbackFor等属性就会被封装到这个类中,允许程序员自己定义回滚的异常,如果没有指定回滚的异常,默认抛出RuntimeException/Error才进行回滚


TransactionStatus


这个接口主要用于描述Spring事务的状态,其继承关系如下:

aHR0cHM6Ly9naXRlZS5jb20vd3hfY2MzNDdiZTY5Ni9ibG9nSW1hZ2UvcmF3L21hc3Rlci9UcmFuc2FjdGlvblN0YXR1cy5wbmc (1).png

TransactionExecution,这个接口也是用于描述事务的状态,TransactionStatus是在其上做的扩展,内部定义了以下几个方法

// 判断当前事务是否是一个新的事务
// 不是一个新事务的话,那么需要加入到已经存在的事务中
boolean isNewTransaction();
// 事务是否被标记成RollbackOnly
// 如果被标记成了RollbackOnly,意味着事务只能被回滚
void setRollbackOnly(); 
boolean isRollbackOnly();
// 是否事务完成,回滚或提交都意味着事务完成了
boolean isCompleted();

SavepointManager,定义了管理保存点(Savepoint)的方法,隔离级别为NESTED时就是通过设置回滚点来实现的,内部定义了这么几个方法

// 创建保存点
Object createSavepoint() throws TransactionException;
// 回滚到指定保存点
void rollbackToSavepoint(Object savepoint) throws TransactionException;
// 移除回滚点
void releaseSavepoint(Object savepoint) throws TransactionException;

TransactionStatus,继承了上面这些接口,额外提供了两个方法

//用于判断当前事务是否设置了保存点
boolean hasSavepoint();
// 这个方法复写了父接口Flushable中的方法
// 主要用于刷新会话
// 对于Hibernate/jpa而言就是调用了其session/entityManager的flush方法
void flush();

小总结:

通过上面的分析我们会发现,TransactionDefinition的主要作用是给出一份事务属性的定义,然后事务管理器根据给出的定义来创建事务,TransactionStatus主要是用来描述创建后的事务的状态

在对TransactionDefinition跟TransactionStatus有一定了解后,我们再回到PlatformTransactionManager接口本身,PlatformTransactionManager作为事务管理器的基础接口只是定义管理一个事务必须的三个方法:开启事务,提交事务,回滚事务,接口仅仅是定义了规范而已,真正做事的还是要依赖它的实现类,所以我们来看看它的继承关系


PlatformTransactionManager的实现类

aHR0cHM6Ly9naXRlZS5jb20vd3hfY2MzNDdiZTY5Ni9ibG9nSW1hZ2UvcmF3L21hc3Rlci9QbGF0Zm9ybVRyYW5zYWN0aW9uTWFuYWdlci5wbmc (1).png

AbstractPlatformTransactionManager,Spring提供的一个事务管理的基类,提供了事务管理的模板,实现了Spring事务管理的一个标准流程

判断当前是否已经存在一个事务

应用合适的事务传播行为

在必要的时候挂起/恢复事务

提交时检查事务是否被标记成为rollback-only

在回滚时做适当的修改(是执行真实的回滚/还是将事务标记成rollback-only)

触发注册的同步回调

在AbstractPlatformTransactionManager提供了四个常见的子类,其说明如下

aHR0cHM6Ly9naXRlZS5jb20vd3hfY2MzNDdiZTY5Ni9ibG9nSW1hZ2UvcmF3L21hc3Rlci9pbWFnZS0yMDIwMDgwNjE5NDY1MDA1MC5wbmc.png

关于事务管理器的详细代码分析放到下篇文章,本文对其有个大概了解即可。


Spring中事务的同步机制


Spring中事务相关的同步机制可以分为两类


  • 资源的同步
  • 行为的同步

什么是资源的同步呢?在一个事务中我们往往会一次执行多个SQL(如果是单条的SQL实际上没有必要开启事务),为了保证事务所有的SQL都能够使用一个数据库连接,这个时候我们需要将数据库连接跟事务进行同步,这个时候数据库连接就是跟这个事务同步的一个资源。


那什么又是行为的同步呢?还是以数据库连接为例子,在事务开启之前我们需要先获取一个数据库连接,同样的在事务提交时我们需要将连接关闭(不一定是真正的关闭,如果是连接池只是归还到连接池中),这个时候关闭连接这个行为也需要跟事务进行同步


那么Spring是如何来管理同步的呢?同样的,Spring也提供了一个同步管理器TransactionSynchronizationManager,这是一个抽象类,其中所有的方法都是静态的,并且所有的方法都是围绕它所申明的几个静态常量字段,如下:

// 这就是同步的资源,Spring就是使用这个完成了连接的同步
private static final ThreadLocal<Map<Object, Object>> resources =
    new NamedThreadLocal<>("Transactional resources");
// TransactionSynchronization完成了行为的同步
// 关于TransactionSynchronization在后文进行分析
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
    new NamedThreadLocal<>("Transaction synchronizations");
// 事务的名称
private static final ThreadLocal<String> currentTransactionName =
    new NamedThreadLocal<>("Current transaction name");
// 事务是否被标记成只读
private static final ThreadLocal<Boolean> currentTransactionReadOnly =
    new NamedThreadLocal<>("Current transaction read-only status");
// 事物的隔离级别
private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
    new NamedThreadLocal<>("Current transaction isolation level");
// 是否真实开启了事务 
private static final ThreadLocal<Boolean> actualTransactionActive =
    new NamedThreadLocal<>("Actual transaction active");

可以看到所有的同步都是通过ThreadLocal实现的,对于ThreadLocal本文不做详细分析,如果对ThreadLocal还不了解的同学也没有关系,对于本文而言你只需要知道ThreadLocal能将资源跟当前线程绑定即可,例如ThreadLocal<Map<Object, Object>> resources这个属性就代表要将一个map绑定到当前线程,它提供了set跟get方法,分别用于将属性绑定到线程上以及获取线程上绑定的属性。


上面的几个变量中除了synchronizations之外其余的应该都很好理解,synchronizations中绑定的是一个TransactionSynchronization的集合,那么这个TransactionSynchronization有什么用呢?我们来看看它的接口定义

public interface TransactionSynchronization extends Flushable {
  // 事务完成的状态
    // 0 提交
    // 1 回滚
    // 2 异常状态,例如在事务执行时出现异常,然后回滚,回滚时又出现异常
    // 就会被标记成状态2
  int STATUS_COMMITTED = 0;
  int STATUS_ROLLED_BACK = 1;
  int STATUS_UNKNOWN = 2;
    // 我们绑定的这些TransactionSynchronization需要跟事务同步
    // 1.如果事务挂起,我们需要将其挂起
    // 2.如果事务恢复,我们需要将其恢复
  default void suspend() {
  }
  default void resume() {
  }
  @Override
  default void flush() {
  }
    // 在事务执行过程中,提供的一些回调方法
  default void beforeCommit(boolean readOnly) {
  }
  default void beforeCompletion() {
  }
  default void afterCommit() {
  }
  default void afterCompletion(int status) {
  }
}

可以看到这个接口就是定义了一些方法,这些个方法可以在事务达到不同阶段后执行,可以认为定义了事务执行过程的一些回调行为,这就是我之前说的行为的同步。


模拟Spring事务的实现


本文的最后一部分希望大家模拟一下Spring事务的实现,我们利用现有的AOP来实现事务的管理。数据库访问我们直接使用jdbc,在模拟之前我们先明确两点


  1. 切点应该如何定义?
  2. 通知要实现什么功能?

我们先说第一个问题,因为是我们自己模拟,所以关于切点的定义我们就设置的尽量简单一些,不妨就直接指定某个包下的所有类。对于第二个问题,我们也不做的过于复杂,在方法执行前开启事务,在方法执行后提交事务并关闭连接,所以我们需要定义一个环绕通知。同时,我们也需要将连接跟事务同步,保证事务中的所有SQL共用一个事务是实现事务管理的必要条件。基于此,我们开始编写代码


我们只需要引入Spring相关的依赖跟JDBC相关依赖即可,该项目仅仅是一个Spring环境下的Java项目,没有Web依赖,也不是SpringBoot项目,项目结构如下:


POM文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.dmz.framework</groupId>
    <artifactId>mybatis</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.15</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>
    </dependencies>
</project>

配置类:

// 开启AOP跟扫描组件即可
@EnableAspectJAutoProxy
@ComponentScan("com.dmz.mybatis.tx_demo")
public class Config {
}

完成事务管理的核心类:

public class TransactionUtil {
    public static final ThreadLocal<Connection> synchronousConnection =
            new ThreadLocal<Connection>();
    private TransactionUtil() {
    }
    public static Connection startTransaction() {
        Connection connection = synchronousConnection.get();
        if (connection == null) {
            try {
                // 这里替换成你自己的连接地址即可
                connection = DriverManager
                        .getConnection("jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8", "root", "123");
                synchronousConnection.set(connection);
                connection.setAutoCommit(false);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return connection;
    }
    public static int execute(String sql, Object... args) {
        Connection connection = startTransaction();
        try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
            if (args != null) {
                for (int i = 1; i < args.length + 1; i++) {
                    preparedStatement.setObject(i, args[i - 1]);
                }
            }
            return preparedStatement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return 0;
    }
    public static void commit() {
        try (Connection connection = synchronousConnection.get()) {
            connection.commit();
            synchronousConnection.remove();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    public static void rollback() {
        try (Connection connection = synchronousConnection.get()) {
            connection.rollback();
            synchronousConnection.remove();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

实际需要事务管理的类

@Component
public class UserService {
    public void saveUser() {
        TransactionUtil.execute
                ("INSERT INTO `test`.`user`(`id`, `name`) VALUES (?, ?)", 100, "dmz");
        // 测试回滚
        // throw new RuntimeException();
    }
}

切面:

@Component
@Aspect
public class TxAspect {
    @Pointcut("execution(public * com.dmz.mybatis.tx_demo.service..*.*(..))")
    private void pointcut() {
    }
    @Around("pointcut()")
    public Object around(JoinPoint joinPoint) throws Throwable {
        // 在方法执行前开启事务
        TransactionUtil.startTransaction();
        // 执行业务逻辑
        Object proceed = null;
        try {
            ProceedingJoinPoint method = (ProceedingJoinPoint) joinPoint;
            proceed = method.proceed();
        } catch (Throwable throwable) {
            // 出现异常进行回滚
            TransactionUtil.rollback();
            return proceed;
        }
        // 方法执行完成后提交事务
        TransactionUtil.commit();
        return proceed;
    }
}

用于测试的主函数:

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ac =
                new AnnotationConfigApplicationContext(Config.class);
        UserService userService = ac.getBean(UserService.class);
        userService.saveUser();
    }
}

具体的测试过程跟测试结果我就不放了,大家把代码拷贝过去自行测试就好了


总结


本文主要介绍了Spring中的事务相关内容,对Spring中的事务抽象机制做了介绍,主要是为了让大家在接下来一篇源码文章中能减轻负担,希望大家可以根据自己理解动手模拟下Spring中事务的实现哦,当你自己去实现的时候肯定会碰到一系列的问题,然后带着这些问题看源码你才能知道Spring为什么要做这些事情!

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
71 2
|
5天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
46 14
|
19天前
|
缓存 安全 Java
Spring高手之路26——全方位掌握事务监听器
本文深入探讨了Spring事务监听器的设计与实现,包括通过TransactionSynchronization接口和@TransactionalEventListener注解实现事务监听器的方法,并通过实例详细展示了如何在事务生命周期的不同阶段执行自定义逻辑,提供了实际应用场景中的最佳实践。
40 2
Spring高手之路26——全方位掌握事务监听器
|
21天前
|
Java 关系型数据库 数据库
京东面试:聊聊Spring事务?Spring事务的10种失效场景?加入型传播和嵌套型传播有什么区别?
45岁老架构师尼恩分享了Spring事务的核心知识点,包括事务的两种管理方式(编程式和声明式)、@Transactional注解的五大属性(transactionManager、propagation、isolation、timeout、readOnly、rollbackFor)、事务的七种传播行为、事务隔离级别及其与数据库隔离级别的关系,以及Spring事务的10种失效场景。尼恩还强调了面试中如何给出高质量答案,推荐阅读《尼恩Java面试宝典PDF》以提升面试表现。更多技术资料可在公众号【技术自由圈】获取。
|
22天前
|
缓存 Java 数据库连接
深入探讨:Spring与MyBatis中的连接池与缓存机制
Spring 与 MyBatis 提供了强大的连接池和缓存机制,通过合理配置和使用这些机制,可以显著提升应用的性能和可扩展性。连接池通过复用数据库连接减少了连接创建和销毁的开销,而 MyBatis 的一级缓存和二级缓存则通过缓存查询结果减少了数据库访问次数。在实际应用中,结合具体的业务需求和系统架构,优化连接池和缓存的配置,是提升系统性能的重要手段。
35 4
|
27天前
|
Java 开发者 Spring
深入解析:Spring AOP的底层实现机制
在现代软件开发中,Spring框架的AOP(面向切面编程)功能因其能够有效分离横切关注点(如日志记录、事务管理等)而备受青睐。本文将深入探讨Spring AOP的底层原理,揭示其如何通过动态代理技术实现方法的增强。
53 8
|
1月前
|
Java 开发者 Spring
Spring高手之路24——事务类型及传播行为实战指南
本篇文章深入探讨了Spring中的事务管理,特别是事务传播行为(如REQUIRES_NEW和NESTED)的应用与区别。通过详实的示例和优化的时序图,全面解析如何在实际项目中使用这些高级事务控制技巧,以提升开发者的Spring事务管理能力。
54 1
Spring高手之路24——事务类型及传播行为实战指南
|
25天前
|
JavaScript Java 关系型数据库
Spring事务失效的8种场景
本文总结了使用 @Transactional 注解时事务可能失效的几种情况,包括数据库引擎不支持事务、类未被 Spring 管理、方法非 public、自身调用、未配置事务管理器、设置为不支持事务、异常未抛出及异常类型不匹配等。针对这些情况,文章提供了相应的解决建议,帮助开发者排查和解决事务不生效的问题。
|
1月前
|
XML Java 数据库连接
Spring中的事务是如何实现的
Spring中的事务管理机制通过一系列强大的功能和灵活的配置选项,为开发者提供了高效且可靠的事务处理手段。无论是通过注解还是AOP配置,Spring都能轻松实现复杂的事务管理需求。掌握这些工具和最佳实践,能
48 3
|
2月前
|
Java 关系型数据库 MySQL
Spring事务失效,我总结了这7个主要原因
本文详细探讨了Spring事务在日常开发中常见的七个失效原因,包括数据库不支持事务、类不受Spring管理、事务方法非public、异常被捕获、`rollbackFor`属性配置错误、方法内部调用事务方法及事务传播属性使用不当。通过具体示例和源码分析,帮助开发者更好地理解和应用Spring事务机制,避免线上事故。适合所有使用Spring进行业务开发的工程师参考。
39 2