【MySQL】15. 事务管理(重点) -- 1

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 【MySQL】15. 事务管理(重点) -- 1

1. CURD不加控制,会有什么问题?

在这里插入图片描述

2. CURD满足什么属性,能解决上述问题?

  1. 买票的过程得是原子的 ?
  2. 买票互相应该不能影响 ?
  3. 买完票应该要永久有效 ?
  4. 买前,和买后都要是确定的状态?

    3. 什么是事务?

    事务就是一组DML语句组成,这些语句在逻辑上存在相关性,这一组DML语句要么全部成功,要么全部失败,是一个整体。MySQL提供一种机制,保证我们达到这样的效果。事务还规定不同的客户端看到的数据是不相同的。
    事务就是要做的或所做的事情,主要用于处理操作量大,复杂度高的数据。

假设一种场景:你毕业了,学校的教务系统后台 MySQL 中,不在需要你的数据,要删除你的所有信息(一般不会), 那么要删除你的基本信息(姓名,电话,籍贯等)的同时,也删除和你有关的其他信息,比如:你的各科成绩,你在校表现,甚至你在论坛发过的文章等。
这样,就需要多条 MySQL 语句构成,那么所有这些操作合起来,就构成了一个事务。

正如我们上面所说,一个 MySQL 数据库,可不止你一个事务在运行,同一时刻,甚至有大量的请求被包装成事务,在向 MySQL 服务器发起事务处理请求。而每条事务至少一条 SQL ,最多很多 SQL ,这样如果大家都访问同样的表数据,在不加保护的情况,就绝对会出现问题。甚至,因为事务由多条 SQL 构成,那么,也会存在执行到一半出错或者不想再执行的情况,那么已经执行的怎么办呢?
所以,一个完整的事务,绝对不是简单的 sql 集合,还需要满足如下四个属性:

  • 原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
  • 一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
  • 隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(
    Readuncommitted )、读提交( read committed )、可重复读( repeatable read )和串行化(
    Serializable )
  • 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

上面四个属性,可以简称为 ACID 。

原子性(Atomicity,或称不可分割性)
一致性(Consistency)
隔离性(Isolation,又称独立性)
持久性(Durability)
在这里插入图片描述

4. 为什么会出现事务

事务被 MySQL 编写者设计出来,本质是为了当应用程序访问数据库的时候,事务能够简化我们的编程模型,不需要我们去考虑各种各样的潜在错误和并发问题.
可以想一下当我们使用事务时,要么提交,要么回滚,我们不会去考虑网络异常了,服务器宕机了,同时更改一个数据怎么办对吧?
因此事务本质上是为了应用层服务的. 而不是伴随着数据库系统天生就有的.
备注:我们后面把 MySQL 中的一行信息,称为一行记录

5. 事务的版本支持

在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务, MyISAM 不支持。
查看数据库引擎

mysql> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine             | Support | Comment                                                        | Transactions | XA   | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| InnoDB             | DEFAULT | Supports transactions, row-level locking, and foreign keys     | YES          | YES  | YES        |
| MRG_MYISAM         | YES     | Collection of identical MyISAM tables                          | NO           | NO   | NO         |
| MEMORY             | YES     | Hash based, stored in memory, useful for temporary tables      | NO           | NO   | NO         |
| BLACKHOLE          | YES     | /dev/null storage engine (anything you write to it disappears) | NO           | NO   | NO         |
| MyISAM             | YES     | MyISAM storage engine                                          | NO           | NO   | NO         |
| CSV                | YES     | CSV storage engine                                             | NO           | NO   | NO         |
| ARCHIVE            | YES     | Archive storage engine                                         | NO           | NO   | NO         |
| PERFORMANCE_SCHEMA | YES     | Performance Schema                                             | NO           | NO   | NO         |
| FEDERATED          | NO      | Federated MySQL storage engine                                 | NULL         | NULL | NULL       |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
9 rows in set (0.00 sec)
mysql> show engines \G -- 行显示
*************************** 1. row ***************************
Engine: InnoDB -- 引擎名称
Support: DEFAULT -- 默认引擎
Comment: Supports transactions, row-level locking, and foreign keys -- 描述
Transactions: YES -- 支持事务
XA: YES
Savepoints: YES -- 支持事务保存点
*************************** 2. row ***************************
Engine: MRG_MYISAM
Support: YES
Comment: Collection of identical MyISAM tables
Transactions: NO
XA: NO
Savepoints: NO
*************************** 3. row ***************************
Engine: MEMORY --内存引擎
Support: YES
Comment: Hash based, stored in memory, useful for temporary tables
Transactions: NO
XA: NO
Savepoints: NO
*************************** 4. row ***************************
Engine: BLACKHOLE
Support: YES
Comment: /dev/null storage engine (anything you write to it disappears)
Transactions: NO
XA: NO
Savepoints: NO
*************************** 5. row ***************************
Engine: MyISAM
Support: YES
Comment: MyISAM storage engine
Transactions: NO -- MyISAM不支持事务
XA: NO
Savepoints: NO
*************************** 6. row ***************************
Engine: CSV
Support: YES
Comment: CSV storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 7. row ***************************
Engine: ARCHIVE
Support: YES
Comment: Archive storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 8. row ***************************
Engine: PERFORMANCE_SCHEMA
Support: YES
Comment: Performance Schema
Transactions: NO
XA: NO
Savepoints: NO
*************************** 9. row ***************************
Engine: FEDERATED
Support: NO
Comment: Federated MySQL storage engine
Transactions: NULL
XA: NULL
Savepoints: NULL
9 rows in set (0.00 sec)

6. 事务提交方式

事务的提交方式常见的有两种:

  • 自动提交
  • 手动提交

查看事务提交方式

mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set (0.00 sec)

用 SET 来改变 MySQL 的自动提交模式:

mysql> set autocommit = 0;      -- SET AUTOCOMMIT=0 禁止自动提交
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | OFF   |
+---------------+-------+
1 row in set (0.00 sec)
mysql> set autocommit = 1;
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set (0.00 sec)

7. 事务常见操作方式

简单银行用户表

  • 提前准备
    [root@iZ0jl69kyvg0h181cozuf5Z ~]# netstat -nltp;
    Active Internet connections (only servers)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
    tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      12388/sshd          
    tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN      550/rpcbind         
    tcp6       0      0 :::3306                 :::*                    LISTEN      14239/mysqld        
    tcp6       0      0 :::111                  :::*                    LISTEN      550/rpcbind
    
    mysqld服务默认是3306端口号 同时mysqld服务是出于启动状态的 mysqld服务服从tcp6协议
## 使用win cmd远程访问Centos 7云服务器,mysqld服务(需要win上也安装了MySQL,这里看到结果即可)
## 注意,使用本地mysql客户端,可能看不到链接效果,本地可能使用域间套接字,查不到链接

在这里插入图片描述
在windows机器上连接不上Centos上的MySQL服务
给大家直接展示结果

Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 3484
Server version: 5.7.33 MySQL Community Server (GPL)
Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement

## 使用netstat查看链接情况,可知:mysql本质是一个客户端进程
[whb@VM-0-3-centos ~]$ sudo netstat -ntp
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
PID/Program name
tcp6 0 0 172.17.0.3:3306 113.132.141.236:19354
ESTABLISHED 30415/mysqld

## 为了便于演示,我们将mysql的默认隔离级别设置成读未提交。
## 具体操作在后续博客会进行介绍,现在以使用为主。
mysql> set global transaction isolation level READ UNCOMMITTED;
Query OK, 0 rows affected (0.00 sec)

mysql> quit
Bye

##需要重启终端,进行查看
mysql> select @@tx_isolation;
+------------------+
| @@tx_isolation   |
+------------------+
| READ-UNCOMMITTED |
+------------------+
1 row in set, 1 warning (0.00 sec)
  • 创建测试表
    create table if not exists account(
    id int primary key,
    name varchar(50) not null default '',
    blance decimal(10,2) not null default 0.0
    )ENGINE=InnoDB DEFAULT CHARSET=UTF8;
    
  • 正常演示 - 证明事务的开始与回滚
    ```c
    mysql> show variables like 'autocommit'; -- 查看事务是否自动提交。我们故意设置成自动提交,看看该选项是否影响begin
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | autocommit | ON |
    +---------------+-------+
    1 row in set (0.00 sec)

mysql> start transaction; -- 开始一个事务begin也可以,推荐begin
Query OK, 0 rows affected (0.00 sec)

mysql> savepoint save1; -- 创建一个保存点save1
Query OK, 0 rows affected (0.00 sec)

mysql> insert into account values (1, '张三', 100); -- 插入一条记录
Query OK, 1 row affected (0.05 sec)

mysql> savepoint save2; -- 创建一个保存点save2
Query OK, 0 rows affected (0.01 sec)

mysql> insert into account values (2, '李四', 10000); -- 再插入一条记录
Query OK, 1 row affected (0.00 sec)

mysql> select * from account; -- 两条记录都在了
+----+--------+----------+
| id | name | blance |
+----+--------+----------+
| 1 | 张三 | 100.00 |
| 2 | 李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)

mysql> rollback to save2; -- 回滚到保存点save2
Query OK, 0 rows affected (0.03 sec)

mysql> select * from account; -- 一条记录没有了
+----+-----+--------+
| id | name| blance |
+----+-----+--------+
| 1 | 张三 | 100.00 |
+----+-----+--------+
1 row in set (0.00 sec)

mysql> rollback; -- 直接rollback,回滚在最开始
Query OK, 0 rows affected (0.00 sec)

mysql> select * from account; -- 所有刚刚的记录没有了
Empty set (0.00 sec)

 - 非正常演示1 - 证明未commit,客户端崩溃,MySQL自动会回滚(隔离级别设置为读未提交)
```c
-- 终端A
mysql> select * from account; -- 当前表内无数据
Empty set (0.00 sec)

mysql> show variables like 'autocommit'; -- 依旧自动提交
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
|    autocommit |    ON |
+---------------+-------+
1 row in set (0.00 sec)

mysql> begin; --开启事务
Query OK, 0 rows affected (0.00 sec)

mysql> insert into account values (1, '张三', 100); -- 插入记录
Query OK, 1 row affected (0.00 sec)

mysql> select * from account; --数据已经存在,但没有commit,此时终端B进行同时查看
+---+------+--------+
| id| name | blance |
+---+------+--------+
| 1 |  张三 | 100.00 |
+---+------+--------+
1 row in set (0.00 sec)
mysql> Aborted -- ctrl + \ 异常终止MySQL
-- 终端B
mysql> select * from account; -- 终端A崩溃前
+---+------+--------+
| id| name | blance |
+---+------+--------+
| 1 |  张三 | 100.00 |
+---+------+--------+
1 row in set (0.00 sec)

mysql> select * from account; -- 终端A(事务A)异常终止后 数据自动回滚
Empty set (0.00 sec)
  • 非正常演示2 - 证明commit了,客户端崩溃,MySQL数据不会在受影响,已经持久化
    ```c
    --终端 A
    mysql> show variables like 'autocommit'; -- 依旧自动提交
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | autocommit | ON |
    +---------------+-------+
    1 row in set (0.00 sec)

mysql> select * from account; -- 当前表内无数据
Empty set (0.00 sec)

mysql> begin; -- 开启事务
Query OK, 0 rows affected (0.00 sec)

mysql> insert into account values (1, '张三', 100); -- 插入记录
Query OK, 1 row affected (0.00 sec)

mysql> commit; --提交事务
Query OK, 0 rows affected (0.04 sec)

mysql> Aborted -- ctrl + \ 异常终止MySQL

```c
--终端 B
mysql> select * from account; --数据存在了,所以commit的作用是将数据持久化到MySQL中
+---+------+--------+
| id| name | blance |
+---+------+--------+
| 1 |  张三 | 100.00 |
+---+------+--------+
1 row in set (0.00 sec)
  • 非正常演示3 - 对比试验。证明begin操作会自动更改提交方式,不会受MySQL是否自动提交影响
    ```c
    -- 终端 A
    mysql> select *from account; --查看历史数据
    +---+------+--------+
    | id| name | blance |
    +---+------+--------+
    | 1 | 张三 | 100.00 |
    +---+------+--------+
    1 row in set (0.00 sec)

mysql> show variables like 'autocommit'; --查看事务提交方式
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
1 row in set (0.00 sec)

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

mysql> show variables like 'autocommit'; --查看关闭之后结果
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | OFF|
+---------------+-------+
1 row in set (0.00 sec)

mysql> begin; --开启事务
Query OK, 0 rows affected (0.00 sec)

mysql> insert into account values (2, '李四', 10000); --插入记录
Query OK, 1 row affected (0.00 sec)

mysql> select *from account; --查看插入记录,同时查看终端B
+----+--------+----------+
| id | name | blance |
+----+--------+----------+
| 1 | 张三 | 100.00 |
| 2 | 李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)

mysql> Aborted --再次异常终止

```c
-- 终端B
mysql> select * from account; --终端A崩溃前
+----+--------+----------+
| id |   name |   blance |
+----+--------+----------+
|  1 |    张三 |   100.00 |
|  2 |    李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)

mysql> select * from account; --终端A崩溃后,自动回滚
+---+------+--------+
| id| name | blance |
+---+------+--------+
| 1 |  张三 | 100.00 |
+---+------+--------+
1 row in set (0.00 sec)
  • 非正常演示4 - 证明单条 SQL 与事务的关系
-- 实验一
-- 终端A
mysql> select * from account;
+---+------+--------+
| id| name | blance |
+---+------+--------+
| 1 |  张三 | 100.00 |
+---+------+--------+
1 row in set (0.00 sec)

mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
|    autocommit |    ON |
+---------------+-------+
1 row in set (0.00 sec)

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

mysql> insert into account values (2, '李四', 10000); --插入记录
Query OK, 1 row affected (0.00 sec)

mysql> select *from account; --查看结果,已经插入。此时可以在查看终端B
+----+--------+----------+
| id |   name |   blance |
+----+--------+----------+
|  1 |    张三 |   100.00 |
|  2 |    李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)
mysql> ^DBye  --ctrl + \ or ctrl + d,终止终端
--终端B
mysql> select * from account; --终端A崩溃前
+----+--------+----------+
| id |   name |   blance |
+----+--------+----------+
|  1 |    张三 |   100.00 |
|  2 |    李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)
mysql> select * from account; --终端A崩溃后
+---+------+--------+
| id| name | blance |
+---+------+--------+
| 1 |  张三 | 100.00 |
+---+------+--------+
1 row in set (0.00 sec)
-- 实验二
--终端A
mysql> show variables like 'autocommit'; --开启默认提交
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
|    autocommit |    ON |
+---------------+-------+
1 row in set (0.00 sec)

mysql> select * from account;
+---+------+--------+
| id| name | blance |
+---+------+--------+
| 1 |  张三 | 100.00 |
+---+------+--------+
1 row in set (0.00 sec)

mysql> insert into account values (2, '李四', 10000);
Query OK, 1 row affected (0.01 sec)

mysql> select *from account; --数据已经插入
+----+--------+----------+
| id |   name |   blance |
+----+--------+----------+
|  1 |    张三 |   100.00 |
|  2 |    李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)

mysql> Aborted --异常终止
--终端B
mysql> select * from account; --终端A崩溃前
+----+--------+----------+
| id |   name |   blance |
+----+--------+----------+
|  1 |    张三 |   100.00 |
|  2 |    李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)
mysql> select * from account; --终端A崩溃后,并不影响,已经持久化。 autocommit起作用
+----+--------+----------+
| id |   name |   blance |
+----+--------+----------+
|  1 |    张三 |   100.00 |
|  2 |    李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)

结论:

  • 只要输入begin或者start transaction,事务便必须要通过commit提交,才会持久化,与是否设置set autocommit无关。
  • 事务可以手动回滚,同时,当操作异常,MySQL会自动回滚
  • 对于 InnoDB 每一条 SQL 语言都默认封装成事务,自动提交。(select有特殊情况,因为MySQL 有 MVCC )
  • 从上面的例子,我们能看到事务本身的原子性(回滚),持久性(commit)
  • 那么隔离性?一致性?

事务操作注意事项

  • 如果没有设置保存点,也可以回滚,只能回滚到事务的开始。直接使用 rollback(前提是事务 还没有提交)
  • 如果一个事务被提交了(commit),则不可以回退(rollback)
  • 可以选择回退到哪个保存点
  • InnoDB 支持事务, MyISAM 不支持事务
  • 开始事务可以使 start transaction 或者 begin
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
6月前
|
监控 关系型数据库 MySQL
《MySQL 简易速速上手小册》第8章:事务管理和锁定策略(2024 最新版)
《MySQL 简易速速上手小册》第8章:事务管理和锁定策略(2024 最新版)
58 1
|
SQL 关系型数据库 MySQL
MySQL操作之事务管理
MySQL操作之事务管理
58 0
|
6月前
|
SQL 关系型数据库 MySQL
【MySQL】16.事务管理(重点) -- 2
【MySQL】16.事务管理(重点) -- 2
41 0
|
5月前
|
存储 关系型数据库 MySQL
深入浅出MySQL事务管理与锁机制
MySQL事务确保数据一致性,ACID特性包括原子性、一致性、隔离性和持久性。InnoDB引擎支持行锁、间隙锁和临键锁,提供四种隔离级别。通过示例展示了如何开启事务、设置隔离级别以及避免死锁。理解这些机制对优化并发性能和避免数据异常至关重要。【6月更文挑战第22天】
349 3
|
6月前
|
缓存 关系型数据库 MySQL
【专栏】提升MySQL性能和高可用性的策略,包括索引优化、查询优化和事务管理
【4月更文挑战第27天】本文探讨了提升MySQL性能和高可用性的策略,包括索引优化、查询优化和事务管理。通过合理使用B-Tree和哈希索引,避免过度索引,以及优化查询语句和利用查询缓存,可以改善性能。事务管理中,应减小事务大小并及时提交,以保持系统效率。主从或双主复制可增强高可用性。综合运用这些方法,并根据实际需求调整,是优化MySQL的关键。
220 2
|
6月前
|
关系型数据库 MySQL 测试技术
【MySQL】事务管理 -- 详解(下)
【MySQL】事务管理 -- 详解(下)
|
6月前
|
SQL 关系型数据库 MySQL
【MySQL】事务管理 -- 详解(上)
【MySQL】事务管理 -- 详解(上)
|
6月前
|
关系型数据库 MySQL 数据库
【MySQL】:数据库事务管理
【MySQL】:数据库事务管理
106 0
|
6月前
|
关系型数据库 MySQL 测试技术
【MySQL】16. 事务管理( 重点 | 选学 ) -- 3
【MySQL】16. 事务管理( 重点 | 选学 ) -- 3
48 0
|
存储 SQL 关系型数据库
MySQL事务管理(三)
MySQL事务管理
90 0