事务介绍及Mysql、jdbc、Spring实现事务

1. 什么是事务

事务是程序的一组操作,要么全部执行成功,要么失败后,所有的操作回到执行前的状态。

事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并用形如begin transaction和end transaction语句(或函数调用)来界定。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。

2. 事务的特性(ACID)

  1. 原子性(atomicity) 一个事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做。
  2. 一致性(consistency) 事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
  3. 隔离性(isolation) 一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对同一时间执行的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
  4. 持久性(durability) 持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

3. 事务的隔离级别

3.1 隔离性说所产生的问题

事务的隔离级别是因为事务是有隔离性的,所以当多个事务并发对一份数据进行操作,很可能会产生一些问题,如脏读、幻读、不可重复读等。

3.1.1 脏读

一个事务可以读取另一个未提交的事务的数据

张三出去吃饭,发现支付软件里没有钱,让李四给他转账100元,当李四给其转账时,转账事务只是修改了数据库张三的金额,还没有提交事务,但是张三已经看到钱包里有100元了,并付款给商家15元,但是李四的转账事务在给张三的余额增加100后,需要给自己账户减去100元时出现问题,导致转账事务回滚,但是张三已经将100元花出去15元,这里就会出现问题

3.1.2 不可重复读

一个事务中前后读到的数据不一致,也就是同一份数据,在一个事务中重复读取,但是数据却不一致,叫做不可重复读。
在A事务第一次读取时发现是余额时0元,B事务并发执行,将余额修改为100元,B事务提交,A事务再次查询后,发现变成了100元,两次查询数据不一致。

张三银行卡里有3000元,张三媳妇拿着银行卡,张三吃饭时用手机支付了15元,在支付时,张三卡上有3000元,但是在同一时间,张三媳妇将卡上3000转到自己的支付软件上,结果在张三付款中,银行发现第一次查询是3000元,但是在减掉余额时,重新查询了一遍,发现是0元

3.1.3 幻读

一个事务第一次看到的数据条目和第二次看到的数据条目不一致,也就是重复读取,发现数据库中的数据条目多了几条或少了几条,就好像出现幻觉,也叫幻读。
在A事务第一次读取时看到数据库表有5条数据,B事务并发执行,新增了一条数据,B事务提交,A事务再次查询时发现是6条数据。

备注:不可重复读和幻读最大的区别:不可重复读是数据值的变化,而幻读是数据条目的变化。

3.2 四种隔离级别

隔离级别 脏读 不可重复度 幻读
未提交读
已提交读
可重复读
串行化

3.2.1 未提交读

字面意思上就可以看出,未提交读就是说A事务还没有提交,其他事务就可以读到A已经修改的数据,肯定会出现脏读。
不可重复读和幻读因为是在A事务执行中,其他事务修改数据后提交事务,A事务就会出现幻读和不可重复读。

3.2.2 已提交读

已提交读是A事务必须提交,其他事务才能读到修改后的数据,解决了脏读,但是不可重复读和幻读并没有解决

3.2.3 可重复读

可重复读是A事务读取到数据后,其他事物修改数据并提交事务,A事务再次读取,但是和第一次读取的数据是一致的,解决了不可重复读,但是并没有解决幻读。

3.2.4 串行化

串行化是将事务串行执行,因为单个执行事务,不存在并发,也就不会出现脏读,幻读,不可重复读了。

备注:mysql默认支持可重复读.

3.2.5 mysql默认可重复读产生的问题

(1) 案例1

事务A修改了数据库中的某一条数据,未提交,事务B并发执行,当事务B对数据库做修改、删除、新增时,由于A事务未提交,B事务等待,当A事务提交后,B事务继续执行修改,B事务是以A事务修改前的数据做原值,导致出具出错

李四银行账户有100元,张三给李四转账100元,事务正在执行的同时,王五也给李四转账100元,因为张三转账事务未提交,王五转账事务等待(事务存在修改操作,所以需要等待张三事务提交),张三转账事务提交后,王五事务是以原来的100元进行修改,导致李四帐户现在有200元,出现问题

解决方案

给B事务查询加锁,加上锁后,B事务查询语句会等待A事务提交后再进行查询,保证了数据的安全性

4.SQL 实现事务

4.1 语法

4.1.1 开启事务(二选一)

begin;
start transaction;

4.1.2 提交事务

commit;

4.1.3 回滚事务

rollback;

4.2 演示

4.2.1 表结构

DROP TABLE IF EXISTS `test_account`;
CREATE TABLE `test_account`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
  `balance` double(11, 0) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of test_account
-- ----------------------------
INSERT INTO `test_account` VALUES (1, '张三', 1000);
INSERT INTO `test_account` VALUES (2, '李四', 1000);

SET FOREIGN_KEY_CHECKS = 1;

在这里插入图片描述

4.2.2 转账事务案例

转账成功

张三向李四转账500元,张三帐户减500,李四帐户加500。

start transaction;
update test_account set balance=balance-500 where username='张三';
update test_account set balance=balance+500 where username='李四';
commit;

在这里插入图片描述

转账失败

张三向李四转账500元,张三帐户减500,李四帐户加500。

start transaction;
update test_account set balance=balance-500 where username='张三';
update test_account set balance=balance+500 where username='李四';
rollback;

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_38306425/article/details/108422770
今日推荐