Python学习之复习MySQL-Day8(事务)

目录

  • 文章声明⭐⭐⭐
  • 让我们开始今天的学习吧!
    • 事务简介
    • 事务操作
      • 模拟转账操作
      • 开启事务
      • 提交事务
      • 回滚事务
      • 查看/设置事务提交方法
      • 实例演示
    • 事务四大特性
    • 并发事务问题
      • 分类
    • 事务隔离级别
      • 分类
      • 查看/设置事务隔离级别
      • 实例演示


文章声明⭐⭐⭐

  1. 该文章为我(有编程语言基础,非编程小白)的 MySQL复习笔记
  2. 知识来源为 B站UP主(黑马程序员)的MySQL课程视频,归纳为自己的语言与理解记录于此并加以实践
  3. 此前我已经学习过了MySQL,现在是在复习阶段,所以不是面向小白的教学文章
  4. 不出意外的话,我大抵会 持续更新
  5. 想要了解前端开发(技术栈大致有:Vue2/3、微信小程序、uniapp、HarmonyOS、NodeJS、Typescript)与Python的小伙伴,可以关注我!谢谢大家!

让我们开始今天的学习吧!

事务简介

事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作当成一个整体,一起向系统提交或撤销操作请求,这意味着这些操作要么同时成功,要么同时失败

最常见的例子就是转账操作

  • 要么成功转账:A的余额-1000并且B的余额+1000
  • 要么转账失败:A和B的余额都不变,和转帐前一致
  • 不允许出现:A已经转账了1000,但是由于网络问题或者系统问题,B没有收到1000转账,这就造成了数据库的数据错乱

MYSQL默认事务自动提交,也就是说,每当执行一条DML语句时,MYSQL会隐式地提交事务


事务操作

模拟转账操作

模拟Richie转账1000给Taylor(未出错,正常情况),操作示例如下:

mysql> select * from account where name = 'Richie'; # 首先查询Richhie账户余额是否足够1000
+----+--------+-------+
| id | name   | money |
+----+--------+-------+
|  1 | Richie |  2000 |
+----+--------+-------+
1 row in set (0.00 sec)

mysql> update account set money = money - 1000 where name = 'Richie'; # 将Richie账户余额-1000
Query OK, 1 row affected (0.03 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update account set money = money + 1000 where name = 'Taylor'; # 将Taylor账户余额+1000
Query OK, 1 row affected (0.03 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from account; # 可以看到数据没问题,转账成功
+----+--------+-------+
| id | name   | money |
+----+--------+-------+
|  1 | Richie |  1000 |
|  2 | Taylor |  3000 |
+----+--------+-------+
2 rows in set (0.00 sec)

模拟Richie转账1000给Taylor(出错了),操作示例如下:

mysql> select * from account;
+----+--------+-------+
| id | name   | money |
+----+--------+-------+
|  1 | Richie |  2000 |
|  2 | Taylor |  2000 |
+----+--------+-------+
2 rows in set (0.00 sec)

mysql> update account set money = money - 1000 where name = 'Richie'; # 将Richie账户余额-1000
Query OK, 1 row affected (0.03 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update account set money = money + 1000 where name = 'Taylor' # 这里我们模拟程序错误
    -> 模拟出错。。。;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '模拟出错。。。' at line 2

mysql> select * from account; # 可以看到数据出现了错乱的现象,Taylor并未收到1000转账
+----+--------+-------+
| id | name   | money |
+----+--------+-------+
|  1 | Richie |  1000 |
|  2 | Taylor |  2000 |
+----+--------+-------+
2 rows in set (0.00 sec)

开启事务

开启事务这个操作,只有在自动提交事务的情形下才能发挥作用

start transaction;
# 或者
begin;

提交事务

commit;

回滚事务

rollback;

查看/设置事务提交方法

mysql> # 查看事务提交方式
mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            1 |
+--------------+
1 row in set (0.03 sec)

mysql> # 关闭自动事务提交(0关闭,1开启)
mysql> set @@autocommit = 0;
Query OK, 0 rows affected (0.03 sec)

mysql> # 开启自动事务提交(0关闭,1开启)
mysql> set @@autocommit = 1;
Query OK, 0 rows affected (0.00 sec)

实例演示

select 语句会自动提交一次事务!!!!!!

mysql> # 关闭自动提交事务
mysql> set @@autocommit = 0;
Query OK, 0 rows affected (0.00 sec)

mysql> # 查看原始数据
mysql> select * from account;
+----+--------+-------+
| id | name   | money |
+----+--------+-------+
|  1 | Richie |  2000 |
|  2 | Taylor |  2000 |
+----+--------+-------+
2 rows in set (0.00 sec)

mysql> # 更改数据
mysql> update account set money = money - 1000 where name = 'Richie';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update account set money = money + 1000 where name = 'Taylor';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> # 再查看数据,此时数据应该还是Richie2000,Taylor2000,只不过因为select语句会自动提交一次事务,所以变成了正常提交过事务后的数据,原表数据应该如下:
+----+--------+-------+
| id | name   | money |
+----+--------+-------+
|  1 | Richie |  2000 |
|  2 | Taylor |  2000 |
+----+--------+-------+

mysql> select * from account; # select语句自动提交了一次事务,数据变为如下:
+----+--------+-------+
| id | name   | money |
+----+--------+-------+
|  1 | Richie |  1000 |
|  2 | Taylor |  3000 |
+----+--------+-------+
2 rows in set (0.00 sec)

模拟出现错误时,回滚事务:

mysql> select * from account; # 先查询原始数据
+----+--------+-------+
| id | name   | money |
+----+--------+-------+
|  1 | Richie |  2000 |
|  2 | Taylor |  2000 |
+----+--------+-------+
2 rows in set (0.00 sec)

mysql> update account set money = money - 1000 where name = 'Richie'; # Richie转账1000
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update account set money = money + 1000 where name = 'Taylor' # 模拟错误
    -> 模拟出现错误。。。;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '模拟出现错误。。。' at line 2
mysql> rollback; # 回滚事务,以至于上次提交事务之前的所有SQL语句都失效
Query OK, 0 rows affected (0.03 sec)

mysql> select * from account; # 再次查询会发现,跟什么事都没发生一样
+----+--------+-------+
| id | name   | money |
+----+--------+-------+
|  1 | Richie |  2000 |
|  2 | Taylor |  2000 |
+----+--------+-------+
2 rows in set (0.00 sec)

事务四大特性

  • 原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败
  • 一致性(Consistency):事务完成时,必须使数据全部保持一致状态
  • 隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行
  • 持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的

并发事务问题

分类

问题 描述
脏读 一个事务读到另一个事务还没有提交的数据
不可重复读 一个事务先后读取同一个记录,但两次读取的数据不同,称之为不可重复读
幻读 一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了一个幻影

事务隔离级别

分类

√:表示会出现这种情况
❌:表示不会出现这种情况

隔离级别 脏读 不可重复读 幻读
read uncommitted
read committed(Oracle默认)
repeatable read(MySQL默认)
serializable(串行化)

事务隔离级别越高,数据越安全,但是性能就越低

查看/设置事务隔离级别

session指的是更改当前会话的事务隔离级别,global指的是更改全局的事务隔离级别

# 查看事务隔离级别
select @@transaction_isolation;
# 设置事务隔离级别,session指的是更改当前会话的事务隔离级别,global指的是更改全局的事务隔离级别
set [session | global] transaction isolation level {read uncommitted | read committed |repeatable read | serializable};

实例演示

这里因为验证的流程比较复杂,大家可以自行尝试验证

大家可以开启两个终端打开登录mysql,从而来模拟两个主机对数据库同时进行操作:
Python学习之复习MySQL-Day8(事务)_第1张图片

你可能感兴趣的:(关于Python,mysql,学习,python)