Spring框架的事务管理

目录

一、Spring框架的事务管理

[1. 全配置文件](#1. 全配置文件)

[1.1 导入pom.xml的依赖](#1.1 导入pom.xml的依赖)

[1.2 编写applicationContext.xml](#1.2 编写applicationContext.xml)

[1.3 编写Account实体类](#1.3 编写Account实体类)

[1.4 编写AccountDao接口](#1.4 编写AccountDao接口)

[1.5 编写AccountDaoImpl实现类](#1.5 编写AccountDaoImpl实现类)

[1.6 编写AccountService接口](#1.6 编写AccountService接口)

[1.7 编写AccountServiceImpl实现类](#1.7 编写AccountServiceImpl实现类)

[1.8 编写TransactionTest测试类](#1.8 编写TransactionTest测试类)

[2. 半注解的方式](#2. 半注解的方式)

[2.1 编写xml配置文件](#2.1 编写xml配置文件)

[2.2 Account实体类](#2.2 Account实体类)

[2.3 AccountDao](#2.3 AccountDao)

[2.4 AccountDaoImpl](#2.4 AccountDaoImpl)

[2.5 AccountService](#2.5 AccountService)

[2.6 AccountServiceImpl](#2.6 AccountServiceImpl)

[2.7 Test类](#2.7 Test类)

[3. 全注解的模式](#3. 全注解的模式)

[3.1 编写配置类SpringConfig](#3.1 编写配置类SpringConfig)

[3.2 AccountDao](#3.2 AccountDao)

[3.3 AccountDaoImpl](#3.3 AccountDaoImpl)

[3.4 AccountService](#3.4 AccountService)

[3.5 AccountServiceImpl](#3.5 AccountServiceImpl)

[3.6 Test测试类](#3.6 Test测试类)

二、Spring事务传播行为

[1. 核心概念](#1. 核心概念)

[2. 七种传播行为](#2. 七种传播行为)

[2.1 REQUIRED(默认)](#2.1 REQUIRED(默认))

[2.1.1 特点](#2.1.1 特点)

[2.2 REQUIRES_NEW](#2.2 REQUIRES_NEW)

[2.2.1 特点](#2.2.1 特点)

[2.2.2 场景](#2.2.2 场景)

[2.3 SUPPORTS](#2.3 SUPPORTS)

[2.3.1 特点](#2.3.1 特点)

[2.3.2 场景](#2.3.2 场景)

[2.4 MANDATORY](#2.4 MANDATORY)

[2.4.1 特点](#2.4.1 特点)

[2.4.2 场景](#2.4.2 场景)

[2.5 NOT_SUPPORTED](#2.5 NOT_SUPPORTED)

[2.5.1 特点](#2.5.1 特点)

[2.5.2 场景](#2.5.2 场景)

[2.6 NEVER](#2.6 NEVER)

[2.6.1 特点](#2.6.1 特点)

[2.6.2 场景](#2.6.2 场景)

[2.7 NESTED(嵌套事务)](#2.7 NESTED(嵌套事务))

[2.7.1 特点](#2.7.1 特点)

[2.7.2 注意](#2.7.2 注意)

[3. 七种事务传播行为总结](#3. 七种事务传播行为总结)


一、Spring框架的事务管理

相比于自己写事务,Spring框架来管理事务更方便,它也有三种方式

全配置文件

半注解

全注解

1. 全配置文件

1.1 导入pom.xml的依赖

XML 复制代码
<dependencies>
    <!-- Spring 核心 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>

    <!-- Spring JDBC -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>

    <!-- Spring 事务 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>

    <!-- AOP 相关 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>aopalliance</groupId>
        <artifactId>aopalliance</artifactId>
        <version>1.0</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.13</version>
    </dependency>

    <!-- MySQL 驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.49</version>
    </dependency>

    <!-- Druid 连接池 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.10</version>
    </dependency>

    <!-- 测试 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.0.2.RELEASE</version>
        <scope>test</scope>
    </dependency>

    <!-- 日志 -->
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.12</version>
    </dependency>
</dependencies>

1.2 编写applicationContext.xml

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--纯xml配置-->
    <!-- 1. 数据源 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql:///spring_db"/>
        <property name="username" value="root"/>
        <property name="password" value="2020"/>
    </bean>
    <!-- 2. 事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 3. 事务通知(Spring 提供) -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="pay" propagation="REQUIRED"/>
            <tx:method name="find*" read-only="true"/>
        </tx:attributes>
    </tx:advice>
    <!-- 4. AOP 配置:把事务织入 -->
    <aop:config>
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.qcby.service.AccountServiceImpl.*(..))"/>
    </aop:config>
    <!-- 5. Service -->
    <bean id="accountService" class="com.qcby.service.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"/>
    </bean>
    <!-- 6. Dao(第二种写法,注入 dataSource) -->
    <bean id="accountDao" class="com.qcby.dao.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"/>
    </bean>

</beans>

1.3 编写Account实体类

java 复制代码
public class Account {
    private Integer id;
    private String name;
    private Double money;

    // getter、setter、toString
}

1.4 编写AccountDao接口

java 复制代码
public interface AccountDao {
    void outMoney(String out, double money);
    void inMoney(String in, double money);
}

1.5 编写AccountDaoImpl实现类

java 复制代码
import org.springframework.jdbc.core.support.JdbcDaoSupport;

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {

    @Override
    public void outMoney(String out, double money) {
        String sql = "update account set money=money-? where name=?";
        getJdbcTemplate().update(sql, money, out);
    }

    @Override
    public void inMoney(String in, double money) {
        String sql = "update account set money=money+? where name=?";
        getJdbcTemplate().update(sql, money, in);
    }
}

1.6 编写AccountService接口

java 复制代码
public interface AccountService {
    void pay(String out, String in, double money);
}

1.7 编写AccountServiceImpl实现类

java 复制代码
public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    @Override
    public void pay(String out, String in, double money) {
        // 扣钱
        accountDao.outMoney(out, money);
        int i = 1 / 0;
        // 加钱
        accountDao.inMoney(in, money);
    }
}

1.8 编写TransactionTest测试类

java 复制代码
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TransactionTest {

    @Autowired
    private AccountService accountService;

    @Test
    public void testPay() {
        // 熊大 → 熊二 转 100
        accountService.pay("熊大", "熊二", 100);
    }
}

2. 半注解的方式

2.1 编写xml配置文件

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- 1. 包扫描 -->
    <context:component-scan base-package="com.qcby"/>

    <!-- 2. 数据源 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql:///spring_db"/>
        <property name="username" value="root"/>
        <property name="password" value="2020"/>
    </bean>

    <!-- 3. 事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 4. 开启事务注解支持 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>

</beans>

2.2 Account实体类

2.3 AccountDao

2.4 AccountDaoImpl

java 复制代码
import javax.sql.DataSource;

@Repository
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {

    @Autowired
    public void setDs(DataSource dataSource) {
        setDataSource(dataSource);
    }
    @Override
    public void outMoney(String out, double money) {
        String sql = "update account set money=money-? where name=?";
        getJdbcTemplate().update(sql, money, out);
    }

    @Override
    public void inMoney(String in, double money) {
        String sql = "update account set money=money+? where name=?";
        getJdbcTemplate().update(sql, money, in);
    }
}

2.5 AccountService

2.6 AccountServiceImpl

java 复制代码
@Service
@Transactional
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountDao accountDao;

    @Override
    public void pay(String out, String in, double money) {
        accountDao.outMoney(out, money);
        // 异常
        int i = 1 / 0;
        accountDao.inMoney(in, money);
    }
}

2.7 Test类

java 复制代码
import com.qcby.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TransactionTest {

    @Autowired
    private AccountService accountService;

    @Test
    public void testPay() {
        // 熊大 → 熊二 转 100
        accountService.pay("张三", "李四", 100);
    }
}

3. 全注解的模式

3.1 编写配置类SpringConfig

java 复制代码
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

@Configuration
@ComponentScan("com.qcby") // 扫描包
@EnableTransactionManagement // 开启事务!!!最重要
public class SpringConfig {

    // 1. 数据源
    @Bean
    public DataSource dataSource() {
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql:///spring_db");
        ds.setUsername("root");
        ds.setPassword("2020");
        return ds;
    }

    // 2. 事务管理器
    @Bean
    public DataSourceTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

3.2 AccountDao

3.3 AccountDaoImpl

java 复制代码
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import javax.sql.DataSource;

@Repository
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {

    // 注入数据源
    @Resource
    public void setDs(DataSource dataSource) {
        setDataSource(dataSource);
    }

    @Override
    public void outMoney(String out, double money) {
        String sql = "update account set money=money-? where name=?";
        getJdbcTemplate().update(sql, money, out);
    }

    @Override
    public void inMoney(String in, double money) {
        String sql = "update account set money=money+? where name=?";
        getJdbcTemplate().update(sql, money, in);
    }
}

3.4 AccountService

3.5 AccountServiceImpl

java 复制代码
import com.qcby.dao.AccountDao;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

@Service
@Transactional // 开启事务!!!
public class AccountServiceImpl implements AccountService {

    @Resource
    private AccountDao accountDao;

    @Override
    public void pay(String out, String in, double money) {
        // 扣钱
        accountDao.outMoney(out, money);

        // 模拟异常 → 事务自动回滚
        int i = 1 / 0;

        // 加钱
        accountDao.inMoney(in, money);
    }
}

3.6 Test测试类

java 复制代码
import com.qcby.config.SpringConfig;
import com.qcby.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class) // 加载配置类
public class TxTest {

    @Resource
    private AccountService accountService;

    @Test
    public void testPay() {
        accountService.pay("小王", "小洋", 100);
    }
}

二、Spring事务传播行为

Spring事务一共有七种传播行为:

1. 核心概念

当前事务:外层方法已有事务

无事务:外层没开事务传播行为

2. 七种传播行为

2.1 REQUIRED(默认)

2.1.1 特点

外层有事务->加入当前事务

外层无事务->新建一个事务场景:90%普通业务都用这个

2.2 REQUIRES_NEW

2.2.1 特点

·不管外层有没有事务,都新建一个独立事务

·外层事务挂起,互不影响

·内层回滚不影响外层,外层回滚也不影响内层

2.2.2 场景

日志记录、异步操作、一定要独立提交的业务

2.3 SUPPORTS

2.3.1 特点

外层有事务:加入

外层无事务:以非事务运行

2.3.2 场景

纯查询方法,有无事务都行

2.4 MANDATORY

2.4.1 特点

外层有事务:加入

外层无事务:直接抛异常

2.4.2 场景

强制必须在事务内运行,不能单独调用

2.5 NOT_SUPPORTED

2.5.1 特点

不管外层有没有事务,都以非事务方式运行

外层事务会被挂起

2.5.2 场景

不需要事务的耗时查询、统计

2.6 NEVER

2.6.1 特点

外层无事务:正常运行

外层有事务:直接抛异常

2.6.2 场景

强制不能在事务里执行的方法

2.7 NESTED(嵌套事务)

2.7.1 特点

外层有事务:

嵌套在当前事务里,有保存点savepoint

内层可以单独回滚,不影响外层

外层回滚,内层必须一起回滚

外层无事务:

自己新建事务

2.7.2 注意

只支持MySQL、不支持部分JTA分布式事务

3. 七种事务传播行为总结

传播行为 外层有事务 外层无事务
REQUIRED 加入 新建
REQUIRES_NEW 新建独立事务 新建
SUPPORTS 加入 非事务
MANDATORY 加入 抛异常
NOT_SUPPORTED 非事务运行 非事务
NEVER 抛异常 非事务
NESTED 嵌套保存点 新建

·一共七种传播行为

·默认REQUIRED

·REQUIRES_NEW是独立事务、互不干扰

·NESTED 是嵌套保存点,内层能单独回滚

·SUPPORTS/MANDATORY/NEVER/NOT_SUPPORTED多用于查询、强制事务校验。

相关推荐
武子康30 分钟前
MultiNet7 每轮都 clean,ESP32-P4 内存为什么还在掉?
人工智能·后端·agent
缓慢更新41 分钟前
AI 辅助生成单测:从接口定义到用例的流水线
java·服务器·前端·网络·数据库·人工智能
超级架构师1 小时前
PRAXO-CORE 2.5.0:用 conformance 和显式边界构建 Go Agent 框架
开发语言·人工智能·后端·golang·ai编程·智能体框架·praxo-core
陈随易1 小时前
AI 运维服务器,安全又可靠的方法
前端·后端·程序员
LMT流氓兔2 小时前
第五单元——第十六课:给书店助手加上网页界面
java·开发语言·jvm·人工智能·oracle·langchain·1024程序员节
IT_陈寒3 小时前
JavaScript的this坑人实录,这次我真的记下来了
前端·人工智能·后端
wangbing11254 小时前
平台介绍-modbus设备调试
java
starzy19904 小时前
Scala类和对象:从构造器到样例类的完整指南
开发语言·后端·scala
开开心心就好4 小时前
音频降噪剪辑工具,音量裁剪一键处理
运维·服务器·前端·spring·ocr·音视频·1024程序员节
梦影_4 小时前
MySQL进阶教程(五)—— SQL调优(下)
android·大数据·数据库·后端·sql·mysql·database