MYSQL 事务(学习笔记)

前言

由现象引入:
在这里插入图片描述

  • 从程序员角度来看 这就是事务中所谓的 “脏读 "

    手机客户端进程里 使用套餐兑换券下单,进入待支付状态后,产生了一个记录,同时微信客户端进程看到了这个记录,微信客户端进程看到的这个记录就是脏数据。微信客户端进程读取了这个脏数据,产生了一条新记录提交了事务。手机客户端再进行了退款操作,回滚了数据。就导致了出现了这个新的兑换券

事务的概念:

数据库的事务(Transaction)是一种机制、一个操作序列,包含了一组数据库操作命令,它由一组相关的dml语句组成。

事务把所有的命令作为一个整体一起向系统提交或撤销操作请求,即这一组数据库命令要么同时成功,要么同时失败。如:转账就要用事务来处理,用以保证数据的一致性。

事务是一个不可分割的工作逻辑单元。


一、事务是什么?

1.举例说明

如下图有一张表

在这里插入图片描述

张三和李四账户中各有100块钱,现李四需要转换500块钱给张三,具体的转账操作为

  • 第一步:查询李四账户余额
  • 第二步:从李四账户金额 -500
  • 第三步:给张三账户金额 +500

现在假设在转账过程中第二步完成后出现了异常第三步没有执行,就会造成李四账户金额少了500,而张三金额并没有多500;这样的系统是有问题的。如果解决呢?使用事务可以解决上述问题

在这里插入图片描述

从上图可以看到在转账前开启事务,如果出现了异常回滚事务,三步正常执行就提交事务,这样就可以完美解决问题。

2.演示事务

-- 事务的一个重要的概念和具体操作
-- 概念:
--一、回退事务
-- 在介绍回退事务之前,先介绍一下保存点(savepoint).保存点是事务中的点,用于取消部分事务,当结束事务(commit),会自动的删除该事务所定义的所有保存点。当执行回退事务时,通过指定保存点可以回退到指定的点。
--二、提交事务
-- 使用commit语句可以提交事务,当执行了commit语句子后,会确认事务的变化、结束事务、删除保存点、释放锁,数据生效。当使用commit语句结束事务子后,其它会话[其它连接]将可以查看到事务变化后的新数据【所有数据就正式生效】
-- 1. 创建一张测试表
CREATE TABLE t27
	( id INT,
	  `name` VARCHAR(32));
-- 2. 开始事务
START TRANSACTION 
-- 3. 设置保存点
SAVEPOINT a
-- 执行dml 操作
INSERT INTO t27 VALUES(100, 'tom');
SELECT * FROM t27;

SAVEPOINT b
-- 执行dml操作
INSERT INTO t27 VALUES(200, 'jack');

-- 回退到 b
ROLLBACK TO b
-- 继续回退 a
ROLLBACK TO a
-- 如果这样, 表示直接回退到事务开始的状态.
ROLLBACK 
COMMIT

3.事务的细节

-- 讨论 事务细节
-- 1. 如果不开始事务,默认情况下,dml操作是自动提交的,不能回滚
INSERT INTO t27 VALUES(300, 'milan'); -- 自动提交 commit

SELECT * FROM t27

-- 2. 如果开始一个事务,你没有创建保存点. 你可以执行 rollback,
-- 默认就是回退到你事务开始的状态
START TRANSACTION 
INSERT INTO t27 VALUES(400, 'king');
INSERT INTO t27 VALUES(500, 'scott');
ROLLBACK -- 表示直接回退到事务开始的的状态
COMMIT;

-- 3. 你也可以在这个事务中(还没有提交时), 创建多个保存点.比如: savepoint 	aaa;    
-- 执行 dml , savepoint  bbb

-- 4. 你可以在事务没有提交前,选择回退到哪个保存点
-- 5. InnoDB 存储引擎支持事务 , MyISAM 不支持
-- 6. 开始一个事务 start  transaction,    set autocommit=off;


二、MYSQL事务的隔离级别

1.事务的隔离级别介绍

在这里插入图片描述

2.设置事务的隔离级别

在这里插入图片描述
在这里插入图片描述
只有关了mysql服务 配置文件才会生效
在这里插入图片描述

3.mysql事务隔离级别-案例

开两个窗口(暂用a,b来代替)来演示事务隔离级别
在这里插入图片描述

涉及到的sql语句

-- 登录数据库
mysql -uroot -p
-- 查看所有数据库
show databates;
-- 查看所有表
show tables;
-- 查看表结构
desc account;
-- 创建表
CREATE TABLE `account`(
	id INT,
	`name` VARCHAR(32),
	money INT);
-- 开启事务
start transaction;
-- 查看当前会话隔离级别
SELECT @@tx_isolation
-- 查看系统当前隔离级别
SELECT @@global.tx_isolation
-- 设置当前会话隔离级别为读未提交
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
-- 设置系统当前隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL [你设置的级别]

3.1、读未提交(Read uncommitted)

--窗口a、b
--1、窗口a、b登录MySQL
mysql -uroot -p
--2、查看事务级别
SELECT @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
--3、窗口a 设置隔离级别为读未提交
 SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
 +------------------+
| @@tx_isolation   |
+------------------+
| READ-UNCOMMITTED |
+------------------+
--4、窗口a、b 开启事务
 start transaction;
--5、窗口b创建account表
--  5.1使用数据库
use db01;
--  5.2创建表
CREATE TABLE `account`(
	id INT,
	`name` VARCHAR(32),
	money INT);
-- 6、窗口b插入数据(演示脏读)
insert into account values(100,'tom',1000);--脏读
--此时并没有提交事务,但是窗口a、b都可以查到这个表多了一个数据  在 select * from account;
select * from account;
+------+------+-------+
| id   | name | money |
+------+------+-------+
|  100 | tom  |  1000 |
+------+------+-------+
--这个就是脏读
-- 7、窗口b修改、添加数据(演示不可重复读和幻读)
update account set money=800 where id=100;--不可重复读
insert into account values(200,'aom',1200);--幻读
--窗口a、b都提交事务
commit;
--一旦提交了事务,在窗口a看到了。这个就是不可重复读和幻读
select * from account;
mysql -uroot -p

3.2、读已提交(Read committed)

-- 1、窗口b开启事务
start transaction;
-- 2、窗口a修改隔离级别为读已提交
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 3、窗口a开启事务
start transaction;
-- 4、窗口b添加数据
insert into account values(300,'mom',1000);
-- 5、查看数据
--在窗口b
 select * from account;
+------+------+-------+
| id   | name | money |
+------+------+-------+
|  100 | tom  |   800 |
|  200 | aom  |  1200 |
|  300 | mom  |  1000 |
+------+------+-------+
--在窗口a 
select * from account;
+------+------+-------+
| id   | name | money |
+------+------+-------+
|  100 | tom  |   800 |
|  200 | aom  |  1200 |
+------+------+-------+
--窗口a的隔离级别为读已提交 没有显示id为300的数据  说明该隔离级别已经不会出现脏读现象了
-- 6、窗口b修改数据(演示不可重复读和幻读) 
update account set money=1800 where id=200;--不可重复读
--窗口a查看
select * from account;
+------+------+-------+
| id   | name | money |
+------+------+-------+
|  100 | tom  |   800 |
|  200 | aom  |  1200 |
+------+------+-------+
-- 窗口b提交事务
commit;
--窗口a再次查看
select * from account;
+------+------+-------+
| id   | name | money |
+------+------+-------+
|  100 | tom  |   800 |
|  200 | aom  |  1800 |
|  300 | mom  |  1000 |
+------+------+-------+
--说明在当前读已提交的隔离级别下 已经出现了不可重复读和幻读

3.3、可重复读(Repeatable read)

-- 1、登录a、窗口 进入数据库
mysql -uroot -p
use db01;
-- 2、a窗口设置隔离级别为可重复读
SET SESSION TRANSACTION ISOLATION LEVEL Repeatable read;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
-- 3、a、b窗口开启事务
start transaction;
-- 4、b窗插入数据
 insert into account values('400','scott',8000);
-- 5、b窗更新数据
update account set money=2800 where id=300;
-- 6、a、b窗查询数据
select * from account;
--a
+------+------+-------+
| id   | name | money |
+------+------+-------+
|  100 | tom  |   800 |
|  200 | aom  |  1800 |
|  300 | mom  |  1000 |
+------+------+-------+
--b
+------+-------+-------+
| id   | name  | money |
+------+-------+-------+
|  100 | tom   |   800 |
|  200 | aom   |  1800 |
|  300 | mom   |  2800 |
|  400 | scott |  8000 |
+------+-------+-------+
-- 7、b窗提交事务后再次查询a、b窗
commit;
select * from account;-- 查询数据未发生改变 即不可重复读、不可幻读

3.4、可串行化(Serializable)[演示重开客户端]

-- 1、重启客户端a 登录mysql
mysql -uroot -p;
-- 2、窗口a开启可串行化 
SET SESSION TRANSACTION ISOLATION LEVEL Serializable;
+----------------+
| @@tx_isolation |
+----------------+
| SERIALIZABLE   |
+----------------+
-- 3、窗口a、b开启事务
start transaction;
-- 4、窗口b插入数据
insert into account values('500','aatt',80000);
-- 5、窗口b更新数据
update account set money=6800 where id=300;
-- 6、重点!  此时a窗口去查询数据 会卡住
mysql> select * from account;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
-- 错误1205 (HY000):锁定等待超时超过;试着重新启动事务
-- 7、只有当b窗口提交事务的时候 a窗口才可以正常查询
commit;--b窗口
select * from account;--a窗口
+------+-------+-------+
| id   | name  | money |
+------+-------+-------+
|  100 | tom   |   800 |
|  200 | aom   |  1800 |
|  300 | mom   |  6800 |
|  400 | scott |  8000 |
|  500 | aatt  | 80000 |
+------+-------+-------+
5 rows in set (0.00 sec)
-- 

三、事务的四大特征

事务的 acid 特性

  • 原子性(Atomicity): 事务是不可分割的最小操作单位,要么同时成功,要么同时失败
  • 一致性(Consistency) :事务完成时,必须使所有的数据都保持一致状态
  • 隔离性(Isolation) :多个事务之间,操作的可见性
  • 持久性(Durability) :事务一旦提交或回滚,它对数据库中的数据的改变就是永久的

总结

1、了解什么是MYSQL事务

事务用于保证书的一致性,它由一组相关的dml语句组成,该组的dml语句要么全部成功,要么全部失败。

2、掌握事务的隔离级别

1、读未提交(Read uncommitted)
2、读已提交(Read committed)
3、可重复读(Repeatable read)
4、可串行化(Serializable)[演示重开客户端]

3、理解事务的四大特性

  • 原子性(Atomicity): 事务是不可分割的最小操作单位,要么同时成功,要么同时失败
  • 一致性(Consistency) :事务完成时,必须使所有的数据都保持一致状态
  • 隔离性(Isolation) :多个事务之间,操作的可见性
  • 持久性(Durability) :事务一旦提交或回滚,它对数据库中的数据的改变就是永久的
  • 9
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值