10-MySQL_事务管理

✨✨ 欢迎大家来到小伞的大讲堂✨✨

🎈🎈养成好习惯,先赞后看哦~🎈🎈

所属专栏:MySQL**
小伞的主页:xiaosan_blog**

gitee:************************************************************许星让 (xu-xingrang) - Gitee.com****************************************************************

制作不易!点个赞吧!!谢谢喵!!

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

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

1.买票的过程得是原子的吧

  1. 买票互相应该不能影响吧

  2. 买完票应该要永久有效吧

4.买前,和买后都要是确定的状态吧

1.什么是事务?

事务就是一组DML语句组成,这些语句在逻辑上存在相关性,**这一组DML语句要么全部成功,要么全部失败,是一个整体。**MySQL提供一种机制,保证我们达到这样的效果。事务还规定不同的客户端看到的数据是不相同的。

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

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

所有,一个完整的事务,绝对不是简单的 sql集合,还需要满足如下四个属性:

1.1 ACID

原子性:一个事务(transaction)中的所有操作,**要么全部完成,要么全部不完成,**不会结束在中间某个环节。**事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,**就像这个事务从来没有执行过一样。

一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。

隔离性:**数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。**事务隔离分为不同级别,包括读未提交(Readuncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化( Serializable )

持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

2.为什么会出现事务

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

备注:我们后面把MySQL 中的一行信息,称为一行记录

sql 复制代码
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)

3.事务提交方式

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

  • 自动提交
  • 手动提交

查看事务提交方式

sql 复制代码
mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set (0.01 sec)

用set改变提交方式

sql 复制代码
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;    #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)

4.事务常见操作方式

sql 复制代码
[root@iZ2vc09opqmjec5hsbsi0aZ ~]# sudo netstat -nltp    默认开启3306 mysqld服务
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      1049/sshd           
tcp6       0      0 :::3306                 :::*                    LISTEN      11478/mysqld        
使用netstat查看链接情况,可知:mysql本质是一个客户端进程

## 为了便于演示,我们将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)

这里我们先看看效果演示

4.1 创建测试表

sql 复制代码
mysql> 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;
Query OK, 0 rows affected (0.01 sec)

4.2 证明事务的开始与回滚

sql 复制代码
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)

4.3 证明未commit,客户端崩溃,MySQL自动会回滚(隔离级别设置为读未提交)

主机A

mysql> insert into account values(1,'张三',100);

Query OK, 1 row affected (0.00 sec)

mysql> Aborted

主机B

mysql> select * from account;

+----+--------+--------+

| id | name | blance |

+----+--------+--------+

| 1 | 张三 | 100.00 |

+----+--------+--------+

1 row in set (0.00 sec)

mysql> select * from account;

Empty set (0.00 sec)

4.4 证明commit了,客户端崩溃,MySQL数据不会在受影响,已经持久化

主机A

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.00 sec)

mysql> Aborted
主机B

mysql> select * from account;

+----+--------+--------+

| id | name | blance |

+----+--------+--------+

| 1 | 张三 | 100.00 |

+----+--------+--------+

1 row in set (0.00 sec)

4.5 证明begin操作会自动更改提交方式,不会受MySQL是否自动提交影响

sql 复制代码
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> Aborted


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

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

4.6 证明单条 SQL 与事务的关系

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,commit进行事务,使用单挑sql语句,我们终止退出,发现并没有插入数据成功,

实验二,我们启动自动提交,如实验一操作,我们发现插入数据成功,形成持久化

结论:

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

注意事项:

  • 如果没有设置保存点,也可以回滚,只能回滚到事务的开始。直接使用 rollback(前提是事务还没有提交)
  • 如果一个事务被提交了(commit),则不可以回退(rollback)
  • 可以选择回退到哪个保存点
  • InnoDB 支持事务,MyISAM 不支持事务
  • 开始事务可以使 start transaction 或者 begin
相关推荐
2501_945424802 小时前
C++构建缓存加速
开发语言·c++·算法
钰衡大师2 小时前
MySQL服务器表导入本地开发环境
服务器·mysql
2401_851272992 小时前
多平台UI框架C++开发
开发语言·c++·算法
朱一头zcy2 小时前
Linux系列04:简单理解inode、硬链接、软链接、挂载的概念
linux·笔记
umeelove352 小时前
【Flask】四、flask连接并操作数据库
数据库·python·flask
楼田莉子2 小时前
C++数据结构:基数树
开发语言·数据结构·c++·学习
m0_518019482 小时前
C++中的命令模式实战
开发语言·c++·算法
ProgramHan2 小时前
十大排行榜——后端语言及要介绍
java·c++·python·php
William_wL_2 小时前
【C++】vector的使用
c++