从 01 开始 从 01 开始
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档

晓林

程序猿,自由职业者,博主,英语爱好者,健身达人
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档
  • JavaSE

  • JavaSenior

  • JavaEE

  • JavaWeb

  • Spring

    • Spring 介绍
    • 程序中的耦合
    • IoC 的概念和作用
    • Spring 中的依赖注入
    • 基于注解的 IoC
    • 使用基于 XML 的 IoC 完成单表的 CRUD
    • 使用基于注解的 IoC 完成单表的 CRUD
    • IoC 的纯注解配置
    • Spring 整合 Junit
    • 事务问题
    • 代理模式
    • AOP 的概念和入门
    • 基于注解的 AOP
    • Spring 的 JdbcTemplate
    • JdBCDaoSupport
    • 基于 XML 的 AOP 实现事务控制
    • 基于注解的 AOP 实现事务控制
    • Spring 的事务控制
    • 基于 XML 的声明式事务控制
    • 基于注解的声明式事务控制
    • 纯注解实现事务控制
    • Spring 编程式事务控制
      • 环境准备
      • 开始配置
      • 在 service 层配置
      • 缺点
      • 源码
    • Spring5 新特性
  • 主流框架

  • SpringMVC

  • SpringBoot

  • Java
  • Spring
2023-05-08
目录

Spring 编程式事务控制

# 180.Spring 编程式事务控制

之前我们都是使用声明式的事务控制,通过配置的方式实现注解;现在讲讲如何通过编程式来实现控制,当然只是简单说说,了解即可,实际开发过程中使用的很少。

 ‍

# 环境准备

本次我们使用之前的案例:Spring 的 事务控制 ,也就是基于 demo17 的分支进行开发 ‍

# 开始配置

首先事务控制都离不开提交和回滚两个动作,所以即使是编程式事务控制,也得配置事务管理器

我们在 bean.xml 中添加如下内容:

<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!-- 注入数据源 -->
    <property name="dataSource" ref="dataSource"/>
</bean>
1
2
3
4
5

‍ Spring 还给我们提供了一个事务模板对象 TransactionTemplate:

<!-- 配置事务模版对象 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
    <!-- 注入事务管理器 -->
    <property name="transactionManager" ref="transactionManager"/>
</bean>
1
2
3
4
5

‍ TransactionTemplate 类中有一个方法叫做 execute:

@Override
@Nullable
public <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 -> rollback
			rollbackOnException(status, ex);
			throw ex;
		}
		catch (Throwable ex) {
			// Transactional code threw unexpected exception -> rollback
			rollbackOnException(status, ex);
			throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
		}
		this.transactionManager.commit(status);
		return result;
	}
}

private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException {
	Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");

	logger.debug("Initiating transaction rollback on application exception", ex);
	try {
		this.transactionManager.rollback(status);
	}
	catch (TransactionSystemException ex2) {
		logger.error("Application exception overridden by rollback exception", ex);
		ex2.initApplicationException(ex);
		throw ex2;
	}
	catch (RuntimeException | Error ex2) {
		logger.error("Application exception overridden by rollback exception", ex);
		throw ex2;
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

‍ 我们重点看第 13 行,有个 action.doInTransaction 方法,并且执行后,如果有异常,就执行 rollbackOnException 方法回滚;在 rollbackOnException 方法中,执行的就是 transactionManager.rollback(status); 方法,最后执行的也是 connection 对象的 rollbank。

如果没有异常,则执行 transactionManager.commit 方法,也就是提交,最后执行的也是 connection 对象的 commit。

这个 action 是一个参数,其类型是 TransactionCallback,是一个接口。

接下来我们就在 service 层中配置。

# 在 service 层配置

我们在 service 实现类添加如下成员变量和 set 方法:

private TransactionTemplate transactionTemplate;

public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
    this.transactionTemplate = transactionTemplate;
}
1
2
3
4
5

‍ 然后配置 bean.xml:注入 transactionTemplate 对象

    <bean id="accountService" class="com.peterjxl.service.impl.AccountServiceImpl">
        <!-- 注入AccountDao -->
        <property name="accountDao" ref="accountDao"/>
        <!-- 注入TransactionTemplate -->
        <property name="transactionTemplate" ref="transactionTemplate"/>
    </bean>
1
2
3
4
5
6

然后我们在 transfer 方法中添加如下代码:也就是在模板对象的 execute 方法中执行事务,并且我们传入一个 TransactionCallback 接口的匿名内部类:

transactionTemplate.execute(new TransactionCallback<Object>() {
    @Override
    public Object doInTransaction(TransactionStatus status) {
        return null;
    }
});
1
2
3
4
5
6

‍ 然后我们将转账的代码中挪到 execute 方法里:

@Override
public void transfer(String sourceName, String targetName, Float money) {
    transactionTemplate.execute(new TransactionCallback<Object>() {
        @Override
        public Object doInTransaction(TransactionStatus status) {
            // 2.1 根据名称查询转出账户
            Account source = accountDao.findAccountByName(sourceName);
            // 2.2 根据名称查询转入账户
            Account target = accountDao.findAccountByName(targetName);
            // 2.3 转出账户减钱
            source.setMoney(source.getMoney() - money);
            // 2.4 转入账户加钱
            target.setMoney(target.getMoney() + money);
            // 2.5 更新转出账户
            accountDao.updateAccount(source);

            int i = 1/0;
            // 2.6 更新转入账户
            accountDao.updateAccount(target);
            return null;
        }
    });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

‍ 此时我们的 transfer 方法,就和模板对象的 execute 方法执行过程很类似。而我们自己的转账的业务逻辑代码,就相当于 execute 方法中,action.doInTransaction 方法内执行的内容。

如果有异常,就会回滚;没有异常才会提交。

然后我们可以测试下能否正常回滚事务,经过测试是可以控制住事务的 ‍

# 缺点

综上,我们就是这样配置事务的,也就是 service 中的每个方法,都要这样配置:

public class AccountServiceImpl implements IAccountService {

    private IAccountDao accountDao;

    private TransactionTemplate transactionTemplate;

    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }

    public void setAccountDao(IAccountDao accountDao) {
        this.accountDao = accountDao;
    }
    @Override
    public Account findAccountById(Integer accountId) {
        return transactionTemplate.execute(new TransactionCallback<Account>() {
            @Override
            public Account doInTransaction(TransactionStatus status) {
                return accountDao.findAccountById(accountId);
            }
        });
    }

    @Override
    public void transfer(String sourceName, String targetName, Float money) {
        transactionTemplate.execute(new TransactionCallback<Object>() {
            @Override
            public Object doInTransaction(TransactionStatus status) {
                // 2.1 根据名称查询转出账户
                Account source = accountDao.findAccountByName(sourceName);
                // 2.2 根据名称查询转入账户
                Account target = accountDao.findAccountByName(targetName);
                // 2.3 转出账户减钱
                source.setMoney(source.getMoney() - money);
                // 2.4 转入账户加钱
                target.setMoney(target.getMoney() + money);
                // 2.5 更新转出账户
                accountDao.updateAccount(source);

                int i = 1/0;
                // 2.6 更新转入账户
                accountDao.updateAccount(target);
                return null;
            }
        });
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

‍ 至此,又多了很多重复代码,变的很不灵活 ‍

# 源码

本项目已将源码上传到 GitHub (opens new window) 和 Gitee (opens new window) 上。并且创建了分支 demo21,读者可以通过切换分支来查看本文的示例代码

上次更新: 2025/6/3 09:31:54
纯注解实现事务控制
Spring5 新特性

← 纯注解实现事务控制 Spring5 新特性→

最近更新
01
学点统计学:轻松识破一本正经的胡说八道
06-05
02
2025 年 5 月记
05-31
03
《贫穷的本质》很棒,但可能不适合你
05-27
更多文章>
Theme by Vdoing | Copyright © 2022-2025 | 粤 ICP 备 2022067627 号 -1 | 粤公网安备 44011302003646 号 | 点击查看十年之约
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式