SSM框架学习——Spring事务管理

Spring事务管理

概念

事务(Transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么都不执行,是一个不可分割的工作单元

事务有如下特性:

  • 原子性
  • 隔离性
  • 一致性
  • 持久性

如果多个事务同时操作同一批数据,则会引发并发异常,设置不同的隔离级别可以解决这些问题。事务的隔离级别如下

隔离界别从小到大,安全性越高,但效率就越低。

事务的传播行为是指在同一个方法中,不同操作前后所使用的事务。传播行为可以控制是否需要创建事务以及如何创建事务,Spring默认传播行为是REQUIRED。

事务的管理方式主要分为两种:

  • 编程式事务管理:通过编写代码实现的事务管理,包括定义事务的开始、正常执行后的事务提交和异常时的事务回滚
  • 声明式事务管理:通过AOP技术实现的事务管理,主要思想是将事务作为一个“切面”代码单独编写,然后通过AOP技术将事务管理的“切面”植入到业务目标类中

为了解耦,我们一般用后者。

声明式事务管理

基于XML

Spring的声明式事务管理可以通过两种方式来实现,一种是基于XML的方式,另一种是基于注解的方式。

基于XML方式的声明式事务是在配置文件中通过<tx:advice>元素配置事务规则来实现的。当配置了事务的增强处理后,就可以通过编写的AOP配置,让Spring自动对目标生成代理。其属性如下。

基于注解

我们更关心基于注解的方式,下面用代码来了解下

我们用之前的top.cairbin.test3项目

app.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.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 指定需要扫描的包,使注解生效 --><context:component-scanbase-package="top.cairbin.test3" /><!-- 配置dataSource --><bean id="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource"><!--数据库驱动 --><property name="driverClassName"value="com.mysql.jdbc.Driver" /><!--连接数据库的url --><property name="url"value="jdbc:mysql://localhost:3306/db_javaee" /><!--连接数据库的用户名 --><property name="username" value="db_javaee" /><!--连接数据库的密码 --><property name="password" value="dbjavaeepassword" /></bean><!-- 2配置JDBC模板 --><bean id="jdbcTemplate"class="org.springframework.jdbc.core.JdbcTemplate"><!-- 默认必须使用数据源 --><property name="dataSource" ref="dataSource" /></bean><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /></bean>	<!-- 注册事务管理器驱动 --><tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

IAccountDao中声明方法

public void transfer(String outUser,String inUser,Double money);

AccountDao类中添加方法及注解

@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false)
public void transfer(String outUser, String inUser, Double money) {// 收款时,收款用户的余额=现有余额+所汇金额this.jdbcTemplate.update("update account set balance = balance +? "+ "where username = ?",money, inUser);// 模拟系统运行时的突发性问题int i = 1/0;// 汇款时,汇款用户的余额=现有余额-所汇金额this.jdbcTemplate.update("update account set balance = balance-? "+ "where username = ?",money, outUser);
}

JdbcTemplateTest测试类中添加测试方法

@Test
public void transTest(){		accountDao.transfer("lisi", "zhangsan", 100.0);// 输出提示信息System.out.println("转账成功!");
}

运行程序前向数据库中插入两条记录,我们使用终端或者sqlyog连接数据库,我这里以Mac的终端为例

mysql -u db_javaee -p

注意这里,我们用的不再是root账户,而是之前创建的db_javaee

输入密码dbjavaeepassword,如果你之前设置的与我不一样这里换成你的密码

输入密码的时候是不显示密码内容的,敲击回车,如果界面跟我下面差不多就说明成功了

后面来写SQL语句,首先把数据库切换到db_javaee下面

USE db_javaee;

如果出现Database changed提示则表示成功。

我们先来查看下之前创建的Account

SELECT * FROM account;

这是我的表里面的内容,你的应该与我不太一样,不过不影响接下来的操作。

我们使用一下语句来插入两条数据

INSERT INTO account(id,username,balance) VALUES(17,'zhangsan',100);
INSERT INTO account(id,username,balance) VALUES(18,'lisi',200);

成功的话会有提示

来看下目前表里的数据

SELECT * FROM account;

接下来我们回到Eclipse IDE,运行我们的代码

运行结果如下

不出意外的话该出意外了,注意看左边的transTest()方法竟然报错,那是正常的,因为我们public void transfer(String outUser, String inUser, Double money);代码写了int i = 1/0;这种语句来模拟报错。

我们到数据库中查看数据

SELECT * FROM account;

很显然数据没有啥变化,我们将transfer方法中的int i = 1/0;删掉试试。注意方法名称,别搞错了。

@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false)
public void transfer(String outUser, String inUser, Double money) {// 收款时,收款用户的余额=现有余额+所汇金额this.jdbcTemplate.update("update account set balance = balance +? "+ "where username = ?",money, inUser);// 模拟系统运行时的突发性问题// int i = 1/0;// 汇款时,汇款用户的余额=现有余额-所汇金额this.jdbcTemplate.update("update account set balance = balance-? "+ "where username = ?",money, outUser);
}

运行一下,发现控制台输出转账成功!

回到数据库查看下

SELECT * FROM account;

下图是操作前后两次的对比,上面是转账成功之前的,后面是转账成功之后的。

数据显然是发生变化了!

问题

到了这里,你可能会有疑问,敲了这么多的代码,我们还不断地进行测试、查看数据库,到底是想干什么。

@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false)
public void transfer(String outUser, String inUser, Double money) {// 收款时,收款用户的余额=现有余额+所汇金额this.jdbcTemplate.update("update account set balance = balance +? "+ "where username = ?",money, inUser);// 模拟系统运行时的突发性问题int i = 1/0;// 汇款时,汇款用户的余额=现有余额-所汇金额this.jdbcTemplate.update("update account set balance = balance-? "+ "where username = ?",money, outUser);
}

我们看看上方的代码。**在前面提到过事务的特性是原子的,也就是不可分割的。**倘若我们没有事务,当this.jdbcTemplate.update(...);这条语句执行的时候,数据库就已经更新了,而int i = 1/0;却出现了一个突发性问题,按理来说我们转账transfer这一方法不应该成立才对,而数据库中的记录的确发生了变动。

如果你是一个恶意用户,然后你发现了这一漏洞,向银行存款,每次存款失败代码异常银行都退回你钱,然后你不断重复这个操作就可以使你的账户余额不断增加,然而你实际上并没有存一分钱进去,这显然是不合理的!

然而我们有了事务,就不会发生这种情况了,因为对于transfer这一操作是不可分割成小操作的,也就是说对于方法里面的东西要么全成功,要么全失败回滚,不可能出现部分成功部分失败这种情况。

结束

Spring初步这一部分就到此为止了,你会发现对于数据库操作在代码里嵌入SQL语句是很麻烦而且不可靠的,如果不做好过滤,用户提交一段包含SQL语句的字符串就有可能利用你的权限操作数据库,还会有安全问题,所以接下来我们将学习MyBatis这个框架。

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

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

相关文章

789. 数的范围 (二分学习)

1.确定一个区间&#xff0c;使得目标值一定在区间中 2.找一个性质满足&#xff1a; &#xff08;1&#xff09;性质具有二段性 &#xff08;2&#xff09;答案是二段性的分界点 3.整数二分&#xff08;处理红色右端点和绿色左端点&#xff09; //代码1&#xff1a;右端点 int…

搜索与图论——Prim算法求最小生成树

在最小生成树问题里&#xff0c;正边和负边都没问题 朴素版prim算法 时间复杂度O(n^2) 生成树&#xff1a;每一次选中的t点&#xff0c;它和集合的距离对应的那条边&#xff0c;就是生成树的一条边 算法流程和dijkstra算法非常相似 #include<iostream> #include<cs…

算法——矩阵,被围绕的区域

. - 力扣&#xff08;LeetCode&#xff09; 最开始也是考虑使用dfs&#xff0c;对于矩阵中的每个点&#xff0c;如果能到达边界的O&#xff0c;则跳过继续dfs。否则如果上下左右四个方向都无法到达边界的O&#xff0c;则说明当前的无法到达&#xff0c;在一个set中记录他的行数…

LLMs 可能在 2 年内彻底改变金融行业

在艾伦图灵研究所&#xff08;The Alan Turing Institute&#xff09;最新的一项研究中&#xff0c;我们看到了大型语言模型&#xff08;Large Language Models&#xff0c;LLMs&#xff09;的一种可能性。它有望通过检测欺诈行为、生成财务洞察以及自动化客户服务&#xff0c;…

十五.PyEcharts常用视图(1)

目录 十二.PyEcharts常用视图(1) 1-PyEcharts-Faker 2-常用视图 2.1 柱状图 普通柱状图 条形柱状图 堆叠柱状图 象形柱状图 颜色自定义 2.2 折线图 基本折线图 折线图常用属性 面积图 堆叠面积图 2.3 散点图 2.4 双轴图 2.5 饼图 基本饼图 空心饼图 玫瑰图…

机器学习实战18-机器学习中XGBClassifier分类器模型的应用实战,以及XGBClassifier分类器的调优策略

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下机器学习实战18-机器学习中XGBClassifier分类器模型的应用实战&#xff0c;以及XGBClassifier分类器的调优策略。XGBClassifier是基于eXtreme Gradient Boosting (XGBoost)算法的分类器模型&#xff0c;在机器学习领…

热榜!基于jsp+mysql的JSP在线水果销售商城系统设计实现【建议收藏】

热榜&#xff01;基于jspmysql的JSP在线水果销售商城系统设计实现【建议收藏】 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《500套》 欢迎…

人工智能+的广泛应用,已渗透到生活的方方面面

引言 随着科技的不断进步和人工智能技术的快速发展&#xff0c;我们正处于一个人工智能时代。人工智能不仅仅是一种技术&#xff0c;更是一种革命性的变革力量&#xff0c;它正在以前所未有的方式改变着我们的生活和工作方式。 人工智能&#xff08;AI&#xff09;指的是人工…

Go 源码之互斥锁 Mutex

文章目录 一、总结二、源码&#xff08;一&#xff09;Mutex&#xff08;二&#xff09; Lock&#xff08;三&#xff09;Unlock 三、常见问题有劳各位看官 点赞、关注➕收藏 &#xff0c;你们的支持是我最大的动力&#xff01;&#xff01;&#xff01;接下来会不断更新 golan…

代码+视频,手动绘制logistic回归预测模型校准曲线(Calibration curve)(1)

校准曲线图表示的是预测值和实际值的差距&#xff0c;作为预测模型的重要部分&#xff0c;目前很多函数能绘制校准曲线。 一般分为两种&#xff0c;一种是通过Hosmer-Lemeshow检验&#xff0c;把P值分为10等分&#xff0c;求出每等分的预测值和实际值的差距. 另外一种是calibra…

Oracle EBS AR接口和OM销售订单单价为空数据修复

最近,用户使用客制化Web ADI 批量导入销售订单行功能,把销售订单行的单价更新成空值,直到发运确认以后,财务与客户对帐才发现大量销售订单的单价空,同时我们检查AR接口发现销售订单的单价和金额均为空。 前提条件 采用PAC成本方式具体问题症状 销售订单行的单价为空 Path:…

C++引用与指针比较

引子&#xff1a; 问题&#xff1a; 指针指向变量必须类型一致&#xff08;int对int*类型指针&#xff09;&#xff0c;这样计算&#xff0c;解引用才能得到正确的结果&#xff0c;那引用也是如此吗&#xff1f; 回答&#xff1a;&#xff08;常引用&#xff09; 从语法来说…