Spring声明式事务管理

Spring 的事务管理有两种方式:一种是传统的编程式事务管理,即通过编写代码实现的事务管理;另一种是基于 AOP 技术实现的声明式事务管理。由于在实际开发中,编程式事务管理很少使用,所以我们只对 Spring 的声明式事务管理进行详细讲解。

Spring 声明式事务管理在底层采用了 AOP 技术,其最大的优点在于无须通过编程的方式管理事务,只需要在配置文件中进行相关的规则声明,就可以将事务规则应用到业务逻辑中。

Spring 实现声明式事务管理主要有两种方式:

	基于 XML 方式的声明式事务管理。通过 Annotation 注解方式的事务管理。

我们通过银行转账的案例讲解如何使用 XML 的方式实现 Spring 的声明式事务处理。

1. 创建项目
在 MyEclipse 中创建一个名为 spring 的 Web 项目,将 Spring 支持和依赖的 JAR 包复制到 Web 项目的 lib 目录中,并添加到类路径下。所添加的 JAR 包如下图所示。

在这里插入图片描述

从上图中可以看出,这里增加导入了 spring-tx-3.2.13.RELEASE.jar(事务管理),以及 MySQL 驱动、JDBC 和 C3P0 的 JAR 包。

2. 创建数据库、表以及插入数据
在 MySQL 中创建一个名为 spring 的数据库,然后在该数据库中创建一个 account 表,并向表中插入两条数据,其 SQL 执行语句如下所示:

CREATE DATABASE spring;
USE spring;
CREATE TABLE account (id INT (11) PRIMARY KEY AUTO_INCREMENT,username VARCHAR(20) NOT NULL,money INT DEFAULT NULL
);
INSERT INTO account VALUES (1,'zhangsan',1000);
INSERT INTO account VALUES (2,'lisi',1000);

执行后的 account 表中的数据如下图所示。

在这里插入图片描述
3. 创建 c3p0-db.properties
在项目的 src 下创建一个名为 c3p0-db.properties 的配置文件,这里使用 C3P0 数据源,需要在该文件中添加如下配置:

jdbc.driverClass = com.mysql.jdbc.Driver
jdbc.jdbcUrl = jdbc:mysql://localhost:3306/spring
jdbc.user = root
jdbc.password = root

4. 实现 DAO

1 创建 AccountDao 接口
在项目的 src 目录下创建一个名为 com.mengma.dao 的包,在该包下创建一个接口 AccountDao,并在接口中创建汇款和收款的方法,如下所示。

package com.mengma.dao;public interface AccountDao {// 汇款public void out(String outUser, int money);// 收款public void in(String inUser, int money);
}

上述代码中,定义了 out() 和 in() 两个方法,分别用于表示汇款和收款。

2 创建DAO层接口实现类
在项目的 src 目录下创建一个名为 com.mengma.dao.impl 的包,在该包下创建实现类 AccountDaoImpl,如下所示。

package com.mengma.dao.impl;import org.springframework.jdbc.core.JdbcTemplate;
import com.mengma.dao.AccountDao;public class AccountDaoImpl implements AccountDao {private JdbcTemplate jdbcTemplate;public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}// 汇款的实现方法public void out(String outUser, int money) {this.jdbcTemplate.update("update account set money =money-?"+ "where username =?", money, outUser);}// 收款的实现方法public void in(String inUser, int money) {this.jdbcTemplate.update("update account set money =money+?"+ "where username =?", money, inUser);}
}

上述代码中,使用 JdbcTemplate 类的 update() 方法实现了更新操作。

5. 实现 Service

1 创建 Service 层接口
在项目的 src 目录下创建一个名为 com.mengma.service 的包,在该包下创建接口 AccountService,如下所示。

package com.mengma.service;public interface AccountService {// 转账public void transfer(String outUser, String inUser, int money);
}

2 创建 Service 层接口实现类
在项目的 src 目录下创建一个名为 com.mengma.service.impl 的包,在该包下创建实现类 AccountServiceImpl,如下所示。

package com.mengma.service.impl;import com.mengma.dao.AccountDao;public class AccountServiceImpl {private AccountDao accountDao;public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;}public void transfer(String outUser, String inUser, int money) {this.accountDao.out(outUser, money);this.accountDao.in(inUser, money);}
}

上述代码中可以看出,该类实现了 AccountService 接口,并对转账的方法进行了实现,根据参数的不同调用 DAO 层相应的方法。

6. 创建 Spring 配置文件
在项目的 src 目录下创建 Spirng 配置文件 applicationContext.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"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd  http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-2.5.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-2.5.xsd"><!-- 加载properties文件 --><context:property-placeholder location="classpath:c3p0-db.properties" /><!-- 配置数据源,读取properties文件信息 --><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="${jdbc.driverClass}" /><property name="jdbcUrl" value="${jdbc.jdbcUrl}" /><property name="user" value="${jdbc.user}" /><property name="password" value="${jdbc.password}" /></bean><!-- 配置jdbc模板 --><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource" /></bean><!-- 配置dao --><bean id="accountDao" class="com.mengma.dao.impl.AccountDaoImpl"><property name="jdbcTemplate" ref="jdbcTemplate" /></bean><!-- 配置service --><bean id="accountService" class="com.mengma.service.impl.AccountServiceImpl"><property name="accountDao" ref="accountDao" /></bean><!-- 事务管理器,依赖于数据源 --><bean id="txManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /></bean><!-- 编写通知:对事务进行增强(通知),需要编写切入点和具体执行事务的细节 --><tx:advice id="txAdvice" transaction-manager="txManager"><tx:attributes><!-- 给切入点方法添加事务详情,name表示方法名称,*表示任意方法名称,propagation用于设置传播行为,read-only表示隔离级别,是否只读 --><tx:method name="find*" propagation="SUPPORTS"rollback-for="Exception" /><tx:method name="*" propagation="REQUIRED" isolation="DEFAULT"read-only="false" /></tx:attributes></tx:advice><!-- aop编写,让Spring自动对目标生成代理,需要使用AspectJ的表达式 --><aop:config><!-- 切入点 --><aop:pointcut expression="execution(* com.mengma.service.*.*(..))"id="txPointCut" /><!-- 切面:将切入点与通知整合 --><aop:advisor pointcut-ref="txPointCut" advice-ref="txAdvice" /></aop:config>
</beans>

上述代码中,首先在 标记的第 6、13 和 14 行代码分别添加了 AOP 所需的命名空间声明。第 42~50 行代码使用 tx:advice 标记配置事务通知内容。

第 52~58 行代码使用 aop:config 标记定义切面,其中第 54 行代码应用了 AspectJ 表达式,代表 com.mengma.service 包下所有类的所有方法都应用事务规则,第 57 行代码使用 aop:advistor 标记将切入点与事务通知整合,基于 AOP 的声明式事务配置完成。

7. 创建测试类
在项目的 src 目录下创建 com.mengma.test 的包,在该包下创建测试类 AccountTest,如下所示。

package com.mengma.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mengma.service.AccountService;
public class AccountTest {@Testpublic void test() {// 获得Spring容器,并操作String xmlPath = "applicationContext.xml";ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);AccountService accountService = (AccountService) applicationContext.getBean("accountService");accountService.transfer("zhangsan", "lisi", 100);}
}

上述代码中模拟了银行转账业务,从 zhangsan 的账户向 lisi 的账户中转入 100 元。使用 JUnit 测试运行 test() 方法,运行成功后,查询 account 表,如下图所示。

从查询结果中可以看出,zhangsan 成功向 lisi 转账 100 元。
在这里插入图片描述

下面通过修改案例模拟转账失败的情况,在的 transfer() 方法中添加一行代码“int i=1/0;”模拟系统断电的情况,具体代码如下所示:

public void transfer(String outUser, String inUser, int money) {this.accountDao.out(outUser, money);//模拟断电int i = 1/0;this.accountDao.in(inUser, money);
}

重新测试运行 test() 方法,JUnit 控制台输出的信息如下图所示。

在这里插入图片描述

从输出结果可以看出,在执行测试方法时,出现了除以 0 的异常信息。此时再次查询 account 表,其查询结果如下图所示。

从查询结果中可以看出,表中的数据并没有发生变化。由于程序在执行过程中抛出了异常,事务不能正常被提交,所以转账失败。由此可知,Spring 的事务管理生效了。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/564488.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python写算法求最短路径,Python实现迪杰斯特拉算法并生成最短路径的示例代码

def Dijkstra(network,s,d):#迪杰斯特拉算法算s-d的最短路径&#xff0c;并返回该路径和代价print("Start Dijstra Path……")path[]#s-d的最短路径nlen(network)#邻接矩阵维度&#xff0c;即节点个数fmax999w[[0 for i in range(n)]for j in range(n)]#邻接矩阵转化…

无法检查指定的位置是否位于cfs上_打印机知识普及:七大原因导致的打印机无法打印及解决方法...

打印机无法打印的原因有很多&#xff0c;如果我们遇到打印机无法打印应该首先从简单到复杂入手。首先必须排除一些最简单的问题&#xff0c;比如打印机是否正常安装。另外打印机内部是不是已经放置有墨盒以及打印纸等&#xff0c;这些基本问题必须排除&#xff0c;另外还有一个…

Spring基于Annotation实现事务管理

在 Spring 中&#xff0c;除了使用基于 XML 的方式可以实现声明式事务管理以外&#xff0c;还可以通过 Annotation 注解的方式实现声明式事务管理。 使用 Annotation 的方式非常简单&#xff0c;只需要在项目中做两件事&#xff0c;具体如下。 1 在 Spring 容器中注册驱动&…

python扩展,用python扩展列

我试图在python中扩展数据帧的某一列。在r中,我将使用这个函数:在python中,我发现df.pivot_table(),但我刚发现一个错误:pandas.pivot_table(df, values Value, index[Day, Money, Product],columns[Account])^更新结果:数据帧没有更改。它只返回相同的数据文件而不进行扩展。考…

基于matlab的pcm系统仿真_深入理解基于RISC-V ISS Spike的仿真系统:探索Spike,pk和fesrv...

Spike, the RISC-V ISA Simulator, implements a functional model of one or more RISC-V processors.Spike is named after the golden spike used to celebrate the completion of the US transcontinental railway.一些同学初接触RISC-V&#xff0c;总逃脱不了被Rocketchip…

think php 子查询,使用thinkPHP怎么实现一个子查询语句

使用thinkPHP怎么实现一个子查询语句发布时间&#xff1a;2021-01-30 13:31:08来源&#xff1a;亿速云阅读&#xff1a;85作者&#xff1a;Leah这篇文章给大家介绍使用thinkPHP怎么实现一个子查询语句&#xff0c;内容非常详细&#xff0c;感兴趣的小伙伴们可以参考借鉴&#x…

python的三个特性_Python3.9的7个特性

作者|PADHMA编译|VK来源|Analytics Vidhya介绍正如著名作家韦恩•W•戴尔所说&#xff0c;改变你看待事物的方式 你所看待的事物也会改变当Python的新版本问世时&#xff0c;许多人担心向后兼容性问题和其他问题。但是如果你喜欢Python&#xff0c;你一定会对新更新中发布的特性…

C++类的成员变量和成员函数

类可以看做是一种数据类型&#xff0c;它类似于普通的数据类型&#xff0c;但是又有别于普通的数据类型。类这种数据类型是一个包含成员变量和成员函数的集合。 类的成员变量和普通变量一样&#xff0c;也有数据类型和名称&#xff0c;占用固定长度的内存。但是&#xff0c;在…

单机安装oracle,单机安装oracle系统

一、安装oracle6.9操作系统1、硬盘划分为30G(以下分区皆强制为主分区)/boot 200Mswap 4G/ 剩余全部空间安装下一步的步骤就不说了勾选图形选项基本系统--》备份客户端&#xff0c;大系统性能&#xff0c;存储工具&#xff0c;安全工具&#xff0c;性能工具&#xff0c;目录客户…

redis timeout设置多少合适_热水器怎么调温度?一般热水器温度设置多少度比较合适?...

对于热水器的温度设置您知道怎么操作吗&#xff1f;一般情况下电热水器设置多少度比较合适呢&#xff1f;今天蜜罐蚁装修网小编给大家介绍下热水器如何调节温度&#xff0c;以及热水器调节温度在什么范围比较合适。下面请看小编以美的电热水器某个型号产品举例图文讲解热水器调…

C++类成员的访问权限以及类的封装

C通过 public、protected、private 三个关键字来控制成员变量和成员函数的访问权限&#xff0c;它们分别表示公有的、受保护的、私有的&#xff0c;被称为成员访问限定符。所谓访问权限&#xff0c;就是你能不能使用该类中的成员。 C 中的 public、private、protected 只能修饰…

oracle数据库12下载地址,Oracle 数据库和补丁下载地址 12.1.0.2 11.2.0.4 11.2.0.1

Oracle 数据库和补丁下载地址 12.1.0.2 11.2.0.4 11.2.0.1 AIX Linux Windows平台AIX 12.1.0.2 DATABASE DB 数据库软件介质下载地址&#xff1a;ftp://104.236.52.210/aix.ppc64_12102_database_1of2.zipftp://104.236.52.210/aix.ppc64_12102_database_2of2.zipAIX 11.2.0.4…

用swing设计一个打地鼠小游戏_这7个风靡欧美的英语小游戏,学会胜过刷100道题!...

精彩导读小编为大家搜罗了一些在国外家喻户晓的语言类小游戏。好的方法胜过刷上100道题&#xff0c;真正让孩子觉得好玩&#xff0c;教学才会事半功倍&#xff01;01Would You Rather...最近牛津大学的面试考题惊天地爆出了一题&#xff1a;你想要变成吸血鬼还是想要变成僵尸&a…

oracle数据库9i安装,Oracle 9i数据库服务器的安装和辅助软件安装教程

安装数据库服务器以Oracle 9i数据库服务器软件的安装过程为例&#xff0c;介绍数据库服务器的安装过程。14.3.1 安装数据库服务器系统环境数据库服务器安装之前&#xff0c;一般都需要检测系统安装环境&#xff0c;以避免系统不支持、内存不够、硬盘空间不足等情况发生。下面从…

python计算排队时间_Python(pdb)-排队执行命令

我正在实现一个“断点”系统以用于我的Python开发,该系统将允许我调用一个实质上调用pdb.set_trace()的函数.我想实现的某些功能要求我在set_trace上下文中时通过代码控制pdb.例&#xff1a;disableList []def breakpoint(nameNone):def d():disableList.append(name)#****#is…

oracle数据库各组件介绍,Oracle 数据库 组件相关说明【第一部分】

参考MOS文档:Information On Installed Database Components and Schemas (文档 ID 472937.1)Oracle 组件可以通过下面的SQL查看&#xff0c;这是我的一个生产库的组件情况&#xff0c;我当时是都部署了&#xff1a;SQL> col COMP_NAME for a50SQL> select comp_id,comp_…

oracle 触发器 行级,oracle的行级触发器使用

行级触发器&#xff1a;当触发器被触发时&#xff0c;要使用被插入、更新或删除的记录中的列值&#xff0c;有时要使用操作前、后列的值.:NEW 修饰符访问操作完成后列的值:OLD 修饰符访问操作完成前列的值例1: 建立一个触发器, 当职工表 emp 表被删除一条记录时&#xff0c;把被…

python include的功能_在Python的Config中增加Include功能

在python中配置文件分析我一般都用configparser。很好&#xff0c;符合我的一贯需求。文本格式、简单、内置。如:[db]hostlocalhostuserdlpasswd12345678[other]因为小程序较多&#xff0c;分别在不同地方&#xff0c;但是都有些共同的配置(如DB的配置)。如果能在配置文件中inc…

oracle的空闲等待事件,Oracle 常见的33个等待事件详解

一&#xff0e; 等待事件的相关知识&#xff1a;1.1 等待事件主要可以分为两类&#xff0c;即空闲(IDLE)等待事件和非空闲(NON-IDLE)等待事件。1). 空闲等待事件指ORACLE正等待某种工作&#xff0c;在诊断和优化数据库的时候&#xff0c;不用过多注意这部分事件。2). 非空闲等待…

python wechatpay微信支付回调_【微信支付】JSAPI支付开发者文档

XXE漏洞需要您在回调处理代码里面解析XML之前&#xff0c;加入禁用实体解析的代码&#xff0c;不同语言设置的内容不同&#xff0c;下面提供了几种主流开发语言的设置指引(您可以根据关键字找到xml解析组件采取对应方法升级)&#xff1a;【PHP】 解析XML代码前加入&#xff1a;…