【Spring】4.Spring的事务管理解析

什么是事务

事务是数据库管理系统中的一个关键概念,用于确保数据的完整性和可靠性。在Spring框架中,事务通常指的是一段代码,这段代码要么完全执行,要么完全不执行,不会出现部分执行的情况。 Spring提供了事务管理的机制,允许开发者以声明式或编程式的方式来控制事务的边界和行为。

事务具有ACID属性,这确保了事务的可靠性:

  1. 原子性(Atomicity):事务中的所有操作要么全部完成,要么全部不完成,不会结束在中间某个点。
  2. 一致性(Consistency):事务必须使数据库从一个一致的状态转移到另一个一致的状态。
  3. 隔离性(Isolation):并发执行的事务之间不会互相影响,每个事务都像是独立执行。
  4. 持久性(Durability):一旦事务提交,则其结果永久保存在数据库中,即使系统发生故障也不会丢失。

Spring的事务管理主要有两种方式:

事务管理

1.声明式事务管理:

通过配置文件或注解来声明事务的边界和特性,利用AOP(面向切面编程)在方法执行前后添加事务管理的逻辑。

在Spring Boot中实现声明式事务管理,涉及到自动配置、自定义配置、事务属性的设置等多个方面。以下是详细的步骤和配置方法:

1. 添加依赖

确保项目中包含了Spring Boot的事务管理和数据库相关依赖。对于JPA,依赖如下:

Maven (pom.xml):

xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <!-- 数据库驱动依赖,例如MySQL -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!-- 其他业务依赖 -->
</dependencies>

Gradle (build.gradle):

gradle 复制代码
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'mysql:mysql-connector-java'
    // 其他业务依赖
}

2. 配置数据源

application.propertiesapplication.yml中配置数据库连接信息:

properties 复制代码
# application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/your_db?useSSL=false
spring.datasource.username=your_username
spring.datasource.password=your_password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

3. 配置实体扫描

创建一个配置类,用于指定实体类的扫描路径,以及配置事务管理器:

java 复制代码
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
    entityManagerFactoryRef = "entityManagerFactory",
    transactionManagerRef = "transactionManager",
    basePackages = {"com.example.domain"} // 实体类的包
)
public class DatabaseConfig {

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
            EntityManagerFactoryBuilder builder, DataSource dataSource) {
        return builder
                .dataSource(dataSource)
                .packages("com.example.domain") // 实体类的包
                .persistenceUnit("default")
                .build();
    }

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}

4. 使用@Transactional注解

在需要事务管理的类或方法上使用@Transactional注解:

java 复制代码
@Service
public class SomeService {

    @Autowired
    private SomeRepository someRepository;

    @Transactional
    public void someServiceMethod() {
        // 业务逻辑,涉及数据库操作
        someRepository.doSomething();
    }
}

5. 配置事务属性

通过@Transactional注解的属性来配置传播行为、隔离级别、超时时间、只读属性和回滚规则:

java 复制代码
@Transactional(
    propagation = Propagation.REQUIRED,
    isolation = Isolation.READ_COMMITTED,
    timeout = 30, // 超时时间,单位为秒
    readOnly = false,
    rollbackFor = Exception.class // 指定哪些异常会导致事务回滚
)
public void someServiceMethod() {
    // 业务逻辑
}

6. 自定义事务管理器

如果需要自定义事务管理器,可以在配置类中添加相应的@Bean方法:

java 复制代码
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(entityManagerFactory);
    // 可以在这里设置其他属性,如超时时间
    return transactionManager;
}

7. 配置事务管理器属性

通过配置文件设置事务管理器的属性,例如JPA的事务超时时间:

properties 复制代码
# application.properties
spring.jpa.properties.hibernate.transaction.manager_lookup_class=org.hibernate.hql.internal.TransactionManagerLookup
spring.transaction.default_timeout=5 # 以秒为单位设置默认的事务超时时间

8. 多数据源事务管理

如果应用中使用了多个数据源,需要为每个数据源配置独立的事务管理器,并在@EnableJpaRepositories注解中指定事务管理器和实体管理器工厂:

java 复制代码
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
    entityManagerFactoryRef = "entityManagerFactorySecondary",
    transactionManagerRef = "transactionManagerSecondary",
    basePackages = {"com.example.domain.secondary"}
)
public class SecondaryDatabaseConfig {

    @Bean(name = "entityManagerFactorySecondary")
    public LocalContainerEntityManagerFactoryBean getEntityManagerFactorySecondary() {
        // 配置第二个数据源的EntityManagerFactoryBean
    }

    @Bean(name = "transactionManagerSecondary")
    public PlatformTransactionManager getTransactionManagerSecondary(EntityManagerFactory entityManagerFactory) {
        // 配置第二个数据源的JpaTransactionManager
    }
}

通过上述步骤,就可以在Spring Boot应用中实现声明式事务管理了,并且可以根据业务需求配置不同的事务属性。Spring Boot的自动配置功能会根据你添加的依赖和配置来自动配置Spring的事务管理器,从而简化了事务管理的复杂性。

2.编程式事务管理:

通过代码直接管理事务的生命周期,如获取和释放事务资源,提交或回滚事务等。

在Spring Boot中实现编程式事务管理,你需要使用TransactionTemplate类。Spring Boot的自动配置机制会为你配置好事务管理器,但编程式事务管理不会自动应用,你需要显式地在你的代码中使用TransactionTemplate

以下是在Spring Boot中实现编程式事务管理的步骤:

1. 配置事务管理器

Spring Boot通常会自动配置事务管理器,但如果你想自定义配置,可以在配置类中添加一个PlatformTransactionManager的Bean。例如,如果你使用的是JPA,Spring Boot会默认配置一个JpaTransactionManager

Java配置示例

java 复制代码
@Configuration
public class DatabaseConfig {

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder, DataSource dataSource) {
        return builder
                .dataSource(dataSource)
                .packages("com.example.domain") // 指定实体类所在的包
                .persistenceUnit("default")
                .build();
    }

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}

2. 配置TransactionTemplate

在你的配置类或服务类中,创建一个TransactionTemplate的Bean,并注入你之前配置的PlatformTransactionManager

Java配置示例

java 复制代码
@Service
public class SomeService {

    @Autowired
    private TransactionTemplate transactionTemplate; // Spring Boot会自动注入

    public void someServiceMethod() {
        // 使用TransactionTemplate执行事务
        transactionTemplate.execute(status -> {
            // 这里编写业务逻辑
            // 这些操作将被事务管理
            return null;
        });
    }
}

3. 设置事务属性

通过TransactionTemplateexecute方法,你可以传递一个TransactionStatus的回调。虽然你不能直接设置传播行为和隔离级别,但你可以在事务管理器的配置中设置这些属性。

例如,对于DataSourceTransactionManager,你可以设置默认的隔离级别:

java 复制代码
@Bean
public DataSourceTransactionManager transactionManager(DataSource dataSource) {
    DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
    transactionManager.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
    return transactionManager;
}

4. 适应不同的业务场景

  • 读取操作 :对于读取操作,如果不需要事务管理,可以使用PROPAGATION_NOT_SUPPORTEDPROPAGATION_NEVER
  • 写入操作 :对于写入操作,默认使用PROPAGATION_REQUIRED
  • 嵌套事务 :对于需要嵌套事务的场景,可以使用PROPAGATION_NESTED

由于编程式事务管理不使用注解,因此事务的传播行为和隔离级别通常在事务管理器的配置中设置。如果你需要更细粒度的控制,可能需要考虑使用声明式事务管理。

在Spring Boot中,推荐使用声明式事务管理,因为它更符合Spring的编程模型,并且易于使用。编程式事务管理通常用于那些不能使用声明式事务管理的场景。

3.事务的属性

在Spring框架中,事务属性定义了事务的特定行为,包括其传播行为、隔离级别、超时设置、只读标志以及回滚规则。以下是Spring支持的主要事务属性:

1. 传播行为(Propagation Behavior)

  • REQUIRED:如果存在一个事务,则加入该事务;如果不存在事务,则创建一个新的事务。
  • SUPPORTS:支持当前事务,如果没有事务则不创建。
  • MANDATORY:必须在一个事务中,否则抛出异常。
  • REQUIRES_NEW:总是创建一个新的事务。
  • NOT_SUPPORTED:不能在事务中执行,如果存在一个活动的事务,则将其挂起。
  • NESTED:如果支持嵌套事务,就创建一个嵌套事务。如果当前事务存在,则嵌套事务是当前事务的子事务。

2. 隔离级别(Isolation Level)

  • ISOLATION_DEFAULT:使用后端数据库的默认隔离级别。
  • ISOLATION_READ_UNCOMMITTED:读未提交。
  • ISOLATION_READ_COMMITTED:读已提交。
  • ISOLATION_REPEATABLE_READ:重复读。
  • ISOLATION_SERIALIZABLE:串行化。

3. 超时属性(Timeout)

  • 以秒为单位设置事务的超时时间。超过这个时间,事务将被回滚。

4. 只读属性(Read-Only)

  • 标记事务为只读事务,这可以给某些事务管理器提供优化的机会。

5. 回滚规则(Rollback Rules)

  • 定义哪些异常会导致事务回滚。可以使用rollbackFornoRollbackFor属性指定。

6. Phase(事务的阶段)

  • 指定事务应该在方法的执行阶段(例如,方法调用之前、调用之后、方法返回时或抛出异常时)。

7. 异步执行(Asynchronous Execution)

  • 在某些事务管理器中,可以配置事务的异步执行。

这些属性可以通过编程式事务管理或声明式事务管理来设置。在声明式事务管理中,通常使用@Transactional注解来设置这些属性,而在编程式事务管理中,则通过TransactionDefinition对象来设置。正确配置事务属性对于确保数据的一致性、隔离性和整体事务管理策略至关重要。理解这些属性及其对事务行为的影响是进行事务管理的关键。

工作原理

Spring中@Transactional注解的工作原理可以概括为以下几个步骤:

1. 注解驱动的事务管理启用

在Spring配置中通过@EnableTransactionManagement注解启用事务管理,这将使得Spring扫描并处理@Transactional注解。

2. 事务属性的配置

使用@Transactional注解标记方法或类,通过注解的参数定义事务的属性,如传播行为、隔离级别、超时时间、只读标志、回滚规则等。

3. 创建代理

Spring容器在创建Bean时,会检测到@Transactional注解。对于被注解的方法,Spring会通过AOP创建一个代理对象(可能是JDK动态代理或CGLIB代理),原始方法的调用会被这个代理对象所包装。

4. 代理对象的调用

当调用一个被@Transactional注解的方法时,实际上是调用了代理对象中的方法。在代理对象内部,Spring框架会在方法执行前后添加事务逻辑。

5. 事务的开始

在代理对象的方法调用之前,Spring会根据定义的事务属性开始一个新的事务或加入到已存在的事务中。

6. 业务逻辑的执行

执行被@Transactional注解的方法中的业务逻辑。

7. 事务的提交或回滚

  • 如果方法正常执行完成,Spring将提交事务。
  • 如果方法执行过程中抛出异常,并且该异常没有被注解的rollbackFor属性排除在外,Spring将回滚事务。

8. 清理

事务完成后,无论是提交还是回滚,Spring都会完成事务的清理工作,包括释放数据库连接等资源。

9. 事务管理器

在整个过程中,PlatformTransactionManager是一个关键的组件,它负责实际的事务管理操作,如获取TransactionStatus,以及根据运行时情况提交或回滚事务。

通过这个流程,@Transactional注解使得Spring能够以声明式的方式管理事务,让开发者可以专注于业务逻辑,而不必显式地处理事务的创建、提交和回滚。

相关推荐
考虑考虑1 小时前
JDK9中的dropWhile
java·后端·java ee
想躺平的咸鱼干1 小时前
Volatile解决指令重排和单例模式
java·开发语言·单例模式·线程·并发编程
hqxstudying1 小时前
java依赖注入方法
java·spring·log4j·ioc·依赖
·云扬·1 小时前
【Java源码阅读系列37】深度解读Java BufferedReader 源码
java·开发语言
春生野草2 小时前
关于SpringMVC的整理
spring
Bug退退退1233 小时前
RabbitMQ 高级特性之重试机制
java·分布式·spring·rabbitmq
小皮侠3 小时前
nginx的使用
java·运维·服务器·前端·git·nginx·github
Zz_waiting.3 小时前
Javaweb - 10.4 ServletConfig 和 ServletContext
java·开发语言·前端·servlet·servletconfig·servletcontext·域对象
全栈凯哥3 小时前
02.SpringBoot常用Utils工具类详解
java·spring boot·后端
兮动人3 小时前
获取终端外网IP地址
java·网络·网络协议·tcp/ip·获取终端外网ip地址