MySQL-----事务管理

news2025/1/24 14:07:18

文章目录

  • 前言
  • 一、什么是事务
  • 二、为什么会出现事务
  • 三、事物的版本支持
  • 四、事物的提交方式
  • 五、事务常见的操作方式
  • 六、事务隔离级别
    • 如何理解隔离性1
    • 隔离级别
      • 查看与设置隔离性
      • 读未提交【Read Uncommitted】
      • 读提交【Read Committed】
      • 可重复读【Repeatable Read】
      • 串行化【serializable】
      • 总结
    • 一致性
  • 七、引出问题
  • 总结


前言

CURD不加控制的时候,会有什么问题呢?

在这里插入图片描述
上层看起来比较简单的需求,可能对应后端要做很多的工作,组合起来才是一个完整的需求解决方案.

一个整体,要么不做,要么做完(绝对成功,绝对失败),不要出现中间操作这样的概念----原子性!!!

上面就称为一个事务!!! 即就是一个或者多个sql语句的集合

事务本身不是数据库软件天然有的,事务本质工作其实是为了简化程序猿的工作模型!

CURD满足什么属性,才能解决上述问题?
1.买票的过程得是原子的吧.
2.买票互相应该不能影响吧.
3.买完票应该要永久有效吧.
4.买前和买后都要是确定的状态吧.


正文开始!!!

一、什么是事务

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

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

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

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

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

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

原子性:(Atomicity,或称为不可分割性).

一致性:(Consistency)

隔离性:(Isolation,又称独立性)

持久性:(Durability)

在这里插入图片描述

二、为什么会出现事务

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

**因此事务本质上是为了应用层服务的.**而不是伴随着数据库天生就有的.

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

三、事物的版本支持

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

查看数据库引擎

mysql> show engines      -- 表格显示
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
          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)

四、事物的提交方式

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

  • 自动提交
  • 手动提交

查看事务提交方式

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

mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | OFF   |
+---------------+-------+
1 row in set (0.01 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.01 sec)

五、事务常见的操作方式

  • 提前准备
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)

## 为了演示,我将MySQL的默认隔离级别设置成读未提交.
mysql> set global transaction isolation level read uncommitted;
Query OK, 0 rows affected (0.00 sec)

mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)

# 需要重启终端进行查看

mysql> quit
Bye
[root@centos7 2023_05_07]# mysql -uroot -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 53
Server version: 5.7.41 MySQL Community Server (GPL)

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

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.

mysql> select @@tx_isolation;
+------------------+
| @@tx_isolation   |
+------------------+
| READ-UNCOMMITTED |
+------------------+
1 row in set, 1 warning (0.00 sec)
  • 创建测试表
mysql> create table if not exists emp(
    -> id int primary key,
    -> name varchar(32) not null,
    -> set decimal(10,2) not null default 0.0
    -> )engine=innodb;
Query OK, 0 rows affected (0.01 sec)

  • 正常演示 - 证明事务的开始与回滚
## 查看事务是否自动提交.我们故意设置成自动提交,看看该选项是否影响begin.
mysql> show variables like 'autocommit';  
+---------------+-------+
| 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 emp values (1, '胡强', 10000.00); -- 插入一条记录
Query OK, 1 row affected (0.05 sec)
mysql> savepoint save2; -- 创建一个保存点save2
Query OK, 0 rows affected (0.01 sec)

mysql> insert into emp values (2, '欧阳莫非', 9000.00); -- 在插入一条记录
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自动会回滚(隔离级别设置为读未提交)
# 终端A
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into emp values (1,'胡强',10000.00);
Query OK, 1 row affected (0.00 sec)

mysql> insert into emp values (2,'欧阳莫非',9000.00);
Query OK, 1 row affected (0.00 sec)

mysql> Aborted


## 终端B
mysql> select * from emp;
+----+--------------+----------+
| id | name         | sal      |
+----+--------------+----------+
|  1 | 胡强         | 10000.00 |
|  2 | 欧阳莫非     |  9000.00 |
+----+--------------+----------+
2 rows in set (0.00 sec)

mysql> select * from emp;
Empty set (0.00 sec)

在这里插入图片描述

  • 非正常演示2 - 证明commit了,客户端崩溃,MySQL数据不会在受影响,已经持久化
## 终端
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into emp values (1,'胡强',10000.00);
Query OK, 1 row affected (0.00 sec)

mysql> insert into emp values (2,'欧阳莫非',9000.00);
Query OK, 1 row affected (0.01 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> Aborted

## 终端B
mysql> select * from emp;
Empty set (0.00 sec)

mysql> select * from emp;
+----+--------------+----------+
| id | name         | sal      |
+----+--------------+----------+
|  1 | 胡强         | 10000.00 |
|  2 | 欧阳莫非     |  9000.00 |
+----+--------------+----------+
2 rows in set (0.00 sec)

mysql> select * from emp;
+----+--------------+----------+
| id | name         | sal      |
+----+--------------+----------+
|  1 | 胡强         | 10000.00 |
|  2 | 欧阳莫非     |  9000.00 |
+----+--------------+----------+
2 rows in set (0.00 sec)

在这里插入图片描述
在这里插入图片描述

  • 非正常演示3 - 对比试验。证明begin操作会自动更改提交方式,不会受MySQL是否自动提交影响
-- 终端 A
mysql> select *from emp; --查看历史数据
+----+--------+--------+
| 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 emp values (2, '李四', 10000); --插入记录
Query OK, 1 row affected (0.00 sec)

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

mysql> Aborted --再次异常终止
-- 终端B
mysql> select * from emp; --终端A崩溃前
+----+--------+----------+
| id | name | blance |
+----+--------+----------+
| 1 | 张三 | 100.00 |
| 2 | 李四 | 10000.00 |
+----+--------+----------+
2 rows in set (0.00 sec)

mysql> select * from emp; --终端A崩溃后,自动回滚
+----+--------+--------+
| id | name | blance |
+----+--------+--------+
| 1 | 张三 | 100.00 |
+----+--------+--------+
1 row in set (0.00 sec)

autocommit是否是自动提交,并不影响用户手动开启事务!!!

  • 非正常演示4 - 证明单挑SQL与事务的关系
## 实验一
-- 终端A
mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set (0.00 sec)

mysql> insert into emp values (3,'苏克杰',8000.00);
Query OK, 1 row affected (0.01 sec)

mysql> insert into emp values (4,'庞小白',8000.00);
Query OK, 1 row affected (0.00 sec)

mysql> quit
Bye

mysql> select * from emp;
Empty set (0.00 sec)

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  3 | 苏克杰    | 8000.00 |
|  4 | 庞小白    | 8000.00 |
+----+-----------+---------+
2 rows in set (0.00 sec)

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  3 | 苏克杰    | 8000.00 |
|  4 | 庞小白    | 8000.00 |
+----+-----------+---------+
2 rows 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> insert into emp values (5,'唐海星',8500.00);
Query OK, 1 row affected (0.00 sec)

mysql> insert into emp values (6,'金若愚',8500.00);
Query OK, 1 row affected (0.00 sec)

mysql> quit
Bye

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  3 | 苏克杰    | 8000.00 |
|  4 | 庞小白    | 8000.00 |
+----+-----------+---------+
2 rows in set (0.00 sec)

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  3 | 苏克杰    | 8000.00 |
|  4 | 庞小白    | 8000.00 |
|  5 | 唐海星    | 8500.00 |
|  6 | 金若愚    | 8500.00 |
+----+-----------+---------+
4 rows in set (0.00 sec)

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  3 | 苏克杰    | 8000.00 |
|  4 | 庞小白    | 8000.00 |
+----+-----------+---------+
2 rows in set (0.00 sec)

## 实验三
mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | OFF   |
+---------------+-------+
1 row in set (0.01 sec)

mysql> insert into emp values (5,'唐海星',8500.00);
Query OK, 1 row affected (0.00 sec)

mysql> insert into emp values (6,'金若愚',8500.00);
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> quit         --终端A退出后,并不影响,已经持久化。autocommit
Bye

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  3 | 苏克杰    | 8000.00 |
|  4 | 庞小白    | 8000.00 |
+----+-----------+---------+
2 rows in set (0.00 sec)

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  3 | 苏克杰    | 8000.00 |
|  4 | 庞小白    | 8000.00 |
|  5 | 唐海星    | 8500.00 |
|  6 | 金若愚    | 8500.00 |
+----+-----------+---------+
4 rows in set (0.00 sec)

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  3 | 苏克杰    | 8000.00 |
|  4 | 庞小白    | 8000.00 |
|  5 | 唐海星    | 8500.00 |
|  6 | 金若愚    | 8500.00 |
+----+-----------+---------+
4 rows in set (0.01 sec)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
结论:

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

事务操作注意事项:

  • 如果没有设置保存点,也可以回滚,只能回滚到事务的开始.直接使用rollback(前提是事务还没有提交)
  • 如果一个事务被提交了(commit),则不可以回滚(rollback).
  • 可以选择回滚到哪个保存点
  • InnoDB支持事务,MyISAM不支持事务.
  • 开始事务可以使用start transaction和begin.

六、事务隔离级别

如何理解隔离性1

  • MySQL服务可能会同时被多个客户端进程 (线程)访问,访问的方式以事务的方式进行.
  • 一个事务可能由多条SQL构成,也就意味着,任何一个事务,都有执行前,执行中,执行后的阶段.而所谓原子性,其实就是让用户层,要么看到执行前,要么看到执行后.执行中出现问题,可以随时回滚.所以单个事务,度用户表现出来的特性,就是原子性.
  • 毕竟所有的事务都要有个执行过程,那么在多个事务各自执行多个SQL的时候,就还是有可能会出现互相影响的情况.比如:多个事务同时访问同一张表,甚至同一行数据.
  • 数据库中,为了保证事务执行过程中禁了不受干扰,就有了一个重要特征:隔离性.
  • 数据库中,允许事务受不同程度的干扰,就有了一种重要特征:隔离级别.

**隔离级别就是在隔离事务这件事情上面,做的不同程度的拖鞋.前提是依旧要保证数据安全.**即就是在效率和可靠性中找平衡.

隔离级别

  • 读未提交[Read Uncommitted] : 在该隔离级别,所有的事务都可以看到其他事务没有提交的执行结果.(实际生产中不可能使用这种隔离级别的),就是相当于没有任何隔离性,也会有很多的并发问题,如脏读,幻读,不可重复读等,我们上面为了做实验方便,用的就是这个隔离性.
  • 读提交[Read committed] : 该隔离级别是大多数数据库的默认隔离级别(不是MySQL默认的).他满足了隔离的简单定义 : 一个事务只能看到其他已经提交的事务所做的改变.这种隔离级别会引起不可重复读,即一个事务执行时,如果多次select,可能得到不同的结果.
  • 可重复读[Repeatable Read] : 这是MySQL默认的隔离级别,他确保同一个事务,在执行中,多次读取操作数据,会看到同样的数据行.但是会有幻读问题.
  • 串行化[Serializable] : 这是事务的最高隔离级别,他通过强制事务排序,使之不可能相互冲突,从而解决了幻读问题.他在每个读的数据行上面加上共享锁.但是可能会导致超时和锁竞争(这种隔离级别太极端,实际生产基本不使用).

隔离级别如何实现:隔离,基本都是通过锁实现的,不同的隔离级别,锁的使用是不同的.常见的有:表锁,行锁,读锁,写锁,间隙锁(GAP),Next-Key锁(GAP+行锁)等.

查看与设置隔离性

-- 查看
mysql> SELECT @@global.tx_isolation; --查看全局隔级别
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ |
+-----------------------+
1 row in set, 1 warning (0.00 sec)
mysql> SELECT @@session.tx_isolation; --查看会话(当前)全局隔级别
+------------------------+
| @@session.tx_isolation |
+------------------------+
| REPEATABLE-READ |
+------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> SELECT @@tx_isolation; --默认同上
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)
--设置
-- 设置当前会话 or 全局隔离级别语法
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ
COMMITTED | REPEATABLE READ | SERIALIZABLE}
--设置当前会话隔离性,另起一个会话,看不多,只影响当前会话
mysql> set session transaction isolation level serializable; -- 串行化
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @@global.tx_isolation; --全局隔离性还是RR
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ |
+-----------------------+
1 row in set, 1 warning (0.00 sec)
mysql> SELECT @@session.tx_isolation; --会话隔离性成为串行化
+------------------------+
| @@session.tx_isolation |
+------------------------+
| SERIALIZABLE |
+------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> SELECT @@tx_isolation; --同上
+----------------+
| @@tx_isolation |
+----------------+
| SERIALIZABLE |
+----------------+
1 row in set, 1 warning (0.00 sec)
--设置全局隔离性,另起一个会话,会被影响
mysql> set global transaction isolation level READ UNCOMMITTED;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| READ-UNCOMMITTED |
+-----------------------+
1 row in set, 1 warning (0.00 sec)
mysql> SELECT @@session.tx_isolation;
+------------------------+
| @@session.tx_isolation |
+------------------------+
| READ-UNCOMMITTED |
+------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> SELECT @@tx_isolation;
+------------------+
| @@tx_isolation |
+------------------+
| READ-UNCOMMITTED |
+------------------+
1 row in set, 1 warning (0.00 sec)
-- 注意,如果没有现象,关闭mysql客户端,重新连接。

读未提交【Read Uncommitted】

--几乎没有加锁,虽然效率高,但是问题太多,严重不建议采用
--终端A
-- 设置隔离级别为 读未提交
mysql> set global transaction isolation level read uncommitted;
Query OK, 0 rows affected (0.00 sec)
--重启客户端
mysql> select @@tx_isolation;
+------------------+
| @@tx_isolation |
+------------------+
| READ-UNCOMMITTED |
+------------------+
1 row in set, 1 warning (0.00 sec)

# 终端A
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> delete from emp where id = 6;
Query OK, 1 row affected (0.00 sec)

--没有commit哦!!!

# 终端B
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  3 | 苏克杰    | 8000.00 |
|  4 | 庞小白    | 8000.00 |
|  5 | 唐海星    | 8500.00 |
|  6 | 金若愚    | 8500.00 |
+----+-----------+---------+
4 rows in set (0.00 sec)

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  3 | 苏克杰    | 8000.00 |
|  4 | 庞小白    | 8000.00 |
|  5 | 唐海星    | 8500.00 |      --读到终端A更新但是未commit的数据[insert,delete同样]
+----+-----------+---------+
3 rows in set (0.00 sec)


## 一个事务在执行中,读到另一个事务的更新(或其他操作)但是为commit的数据,这种现象叫做脏读(dirty read).

在这里插入图片描述

读提交【Read Committed】

mysql> select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+
1 row in set, 1 warning (0.01 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> delete from emp where id=6;
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

## 终端B
mysql> select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+
1 row in set, 1 warning (0.00 sec)

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  3 | 苏克杰    | 8000.00 |
|  4 | 庞小白    | 8000.00 |
|  5 | 唐海星    | 8500.00 |
|  6 | 金若愚    | 8500.00 |
+----+-----------+---------+
4 rows in set (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  3 | 苏克杰    | 8000.00 |
|  4 | 庞小白    | 8000.00 |
|  5 | 唐海星    | 8500.00 |
|  6 | 金若愚    | 8500.00 |
+----+-----------+---------+
4 rows in set (0.00 sec)

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  3 | 苏克杰    | 8000.00 |
|  4 | 庞小白    | 8000.00 |
|  5 | 唐海星    | 8500.00 |
+----+-----------+---------+
3 rows in set (0.00 sec)


## 读提交有问题吗???
## 不应该被正在和你一起运行的事务看到
## 这个下现象叫做不可重复读(non reapeatable raed)!!
## 这个现象是一个问题!!!



在这里插入图片描述

可重复读【Repeatable Read】

--终端A
mysql> set global transaction isolation level repeatable read; --设置全局隔离级别
RR
Query OK, 0 rows affected (0.01 sec)
--关闭终端重启
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ | --隔离级别RR
+-----------------+
1 row in set, 1 warning (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> delete from where id=3;
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 'where id=3' at line 1
mysql> delete from emp where id=3;
Query OK, 1 row affected (0.00 sec)

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  4 | 庞小白    | 8000.00 |
|  5 | 唐海星    | 8500.00 |
+----+-----------+---------+
2 rows in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)


## 终端B
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  3 | 苏克杰    | 8000.00 |
|  4 | 庞小白    | 8000.00 |
|  5 | 唐海星    | 8500.00 |
+----+-----------+---------+
3 rows in set (0.00 sec)

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  3 | 苏克杰    | 8000.00 |
|  4 | 庞小白    | 8000.00 |
|  5 | 唐海星    | 8500.00 |
+----+-----------+---------+
3 rows in set (0.00 sec)


## 实验二
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> delete from emp where id=10;
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> 

## 终端B
mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  4 | 庞小白    | 8000.00 |
|  5 | 唐海星    | 8500.00 |
| 10 | 沙乐乐    | 5000.00 |
+----+-----------+---------+
3 rows in set (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  4 | 庞小白    | 8000.00 |
|  5 | 唐海星    | 8500.00 |
+----+-----------+---------+
2 rows in set (0.00 sec)

## 可重复读本质其实就在一个事务内部,不受任何事务操作的影响,每次查到的数据都是一致的!!!

在这里插入图片描述
在这里插入图片描述

串行化【serializable】

## 对所有操作全部加锁,进行串行化,不会有问题,但是只要串行化,效率很低,几乎完全不会被采用.
## 终端A
mysql> set global transaction isolation level serializable;
Query OK, 0 rows affected (0.00 sec)

mysql> select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| SERIALIZABLE |
+----------------+
1 row in set, 1 warning (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  4 | 庞小白    | 8000.00 |
|  5 | 唐海星    | 8500.00 |
+----+-----------+---------+
2 rows in set (0.00 sec)

mysql> insert into emp values (10,'沙乐乐',5000.00);

## 终端B
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  4 | 庞小白    | 8000.00 |
|  5 | 唐海星    | 8500.00 |
+----+-----------+---------+
2 rows in set (0.00 sec)

--提交之后,终端A中的insert才会提交。

在这里插入图片描述
在这里插入图片描述

总结

  • 其中隔离级别越严格,安全性越高,但数据库的并发性能也就越低,往往需要在两者之间找一个平衡点.
  • 不可重复读的重点是修改和删除 : 同样的条件,你读取过的数据,再次读取出来发现值不一样了.(幻读的重点在于新增 : 同样的条件,第一次和第二次读出来的记录数不一样)
  • 说明:MySQL默认的隔离级别是可重复读,一般情况下不要修改
  • 上面的例子可以看出,事务也有长短事务这样的概念.事务间互相影响,指的是事务在并行执行的时候,即都没有commit的时候,影响会比较大.

在这里插入图片描述

一致性

  • 事务执行的结果,必须使数据库从一个一致性状态,变到另一个一致性状态.当数据库只包含事务成功提交的结果时,数据库处于一致性状态.如果系统运行发生终端,某个事务尚未完成而被迫中断,而改未完成的事务对数据库所做的修改已被写入数据库,此时数据库就处于一种不正确(不一致)的状态.因此一致性是通过原子性来保证的.
  • 其实一致性和用户的业务逻辑强相关,一般MySQL提供技术支持,但是一致性还是要用户业务逻辑做支撑,也就是一致性是由用户决定的.
  • 而技术上,通过AID保证C.

七、引出问题

## 终端A
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  4 | 庞小白    | 8000.00 |
|  5 | 唐海星    | 8500.00 |
+----+-----------+---------+
2 rows in set (0.00 sec)

mysql> update emp set name='Lisa' where id=5;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  4 | 庞小白    | 8000.00 |
|  5 | 袁周率    | 8500.00 |
+----+-----------+---------+
2 rows in set (0.00 sec)

## 终端B
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  4 | 庞小白    | 8000.00 |
|  5 | 唐海星    | 8500.00 |
+----+-----------+---------+
2 rows in set (0.00 sec)

mysql> update emp set name='袁周率' where id=5;
Query OK, 1 row affected (40.34 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from emp;
+----+-----------+---------+
| id | name      | sal     |
+----+-----------+---------+
|  4 | 庞小白    | 8000.00 |
|  5 | 袁周率    | 8500.00 |
+----+-----------+---------+
2 rows in set (0.00 sec)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

现象结果是,update,insert,delete之间是会有加锁现象的,但是select和这些操作是不冲突的。这就是通过读写锁(锁有行锁或者表锁)+MVCC完成隔离性。


总结

以上就是今天要讲的内容,下篇博客我来给大家基于多版本控制(MVCC)解决上述问题!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/521599.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ChatGPT 联网和插件功能,下周起可直接使用,无需排队!

夕小瑶科技说 分享 来源 | 新智元 OpenAI和谷歌,已经打得急红了眼,ChatGPT Plus用户,下周就可以体验联网和插件功能,无需再排队。鲨疯了,真的鲨疯了! ChatGPT,下周开始联网,并开放插…

DAY 57 MySQL数据库的事务

事务的概念 事务是一种机制、一个操作序列,包含了一组数据库操作命令,并且把所有的命令作为一个 整体一起向系统提交或撤销操作请求,即这一组数据库命令要么都执行,要么都不执行。事务是一个不可分割的工作逻辑单元,在…

Python突破JS加密限制,进行逆向解密

前言 嗨喽~大家好呀,这里是魔王呐 ❤ ~! 目录标题 前言开发环境:模块使用:逆向目标逆向过程参数 JS 加密关键代码Python 登录关键代码尾语 💝 开发环境: Python 3.8 Pycharm 模块使用: time >>> 时间模块,属于内置,无…

lol由于找不到vcruntine140_1.dll文件,vcruntime140_1.dll修复方法

家人们有没有遇到过打开游戏或者软件提示由于找不到vcruntime140_1.dll,无法继续执行此代码的情况,是不是不知道怎么修复呢?Vcruntime140_1.dll是一个Windows系统文件,它是Microsoft Visual C Redistributable for Visual Studio …

快速搭建测ceph

一、cephadm介绍 Cephadm是一个由Ceph社区维护的工具,它用于在Ceph集群中管理和部署Ceph服务。它是一个基于容器化的工具,使用了容器技术来部署Ceph集群的不同组件。 使用Cephadm,管理员可以通过简单的命令行界面在整个Ceph集群中进行自动化…

Python递归树结构,回溯法深度优先、广度优先详解,代码实现

Python实现,递归算法,深度优先、广度优先 其实递归说白了就是循环本身函数,只不过下次循环的输入值是上次循环的结果值。关于递归算法,我经常把它用在搜索、计算中。我们来看一个简单的例子: 计算Demo 要实现1&…

高数杂项1

一些口诀 长杠变短杠,开口换方向 其实意思是底下这个 C ∩ D ‾ C ‾ ∪ D ‾ \overline{C \cap D} \overline C \cup \overline D C∩DC∪D 可导必可微,可微必可导 二者互为充要条件 可导必定连续,连续未必可导。连续必定可积,可微未必可积…

django-restful-framework基础知识

DRF 总体设计框架流程 DRF大体的工作流程如下图: 其中:这里的Request不再是Django默认的HttpRequest对象,而是REST Framework提供的扩展了HttpRequest类的Request类对象。 1. Web应用模式 在开发Web应用中,有两种应用模式&…

【sentinel】授权规则详解及源码分析

之前我们在配置流控规则时,可以根据origin参数来对调用方进行限流。 很多时候,我们需要根据调用方来限制资源是否通过,这时候可以使用Sentinel的黑白名单控制的功能,这就是授权规则。 黑白名单也是根据资源的请求来源&#xff0…

vite跨域问题,你可能需要看这篇文章

最近在学习项目的时候,使用了vite工具进行构建,然后出现了跨域的问题,中间的曲折不过多叙述,直接进入正题。 前端成功启动后的界面: 然后在后端进行的Controller上使用了如下的配置 然后浏览器就会出现跨域的问题 为什…

Maven 依赖管理 学习

目录 Maven 依赖管理 可传递性依赖发现 依赖范围 依赖管理 Maven 自动化部署 问题描述 解决方案 修改项目的 pom.xml Maven Release 插件 Maven Web 应用 创建 Web 应用 构建 Web 应用 部署 Web 应用 Maven 依赖管理 Maven 一个核心的特性就是依赖管理。当我们处…

【场景生成与研究】考虑时序相关性MC的场景生成与削减研究(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

Docker基础篇(下)

1、容器命令 新建启动容器 docker run [OPTIONS] IMAGE [COMMAND] [ARG...]常用的参数: ● --name:为容器指定一个名称 ● -d:后台运行容器并返回容器ID,也即启动守护式容器 ● -i:以交互模式(interacti…

基于FPGA:运动目标检测(LCD显示+串口输出,纯Verilog工程)

目录 前言一、先看效果二、硬件选择三、系统框架四、程序模块1、系统顶层模块2、图像处理顶层模块3、LCD驱动顶层模块4、SDRAM控制器顶层模块5、上位机发送模块 五、工程及套件获取1、工程获取2、套件 前言 最早做了基于FPGA:运动目标检测(VGA显示&#…

Java基础-面向对象总结(1)

本文主要梳理关于 Java面向对象的基础知识,希望对你有帮助 Java对象 目录 Java对象 Java创建对象有几种方式 创建一个对象用什么运算符? 对象实体与对象引用有何不同? 创建一个对象的步骤 Java对象都包含什么 ? new Object()对象占多少个字节? 对象的比较 对象的相…

kafka原理之生产者

batch.size:只有数据累计到batch.size后,sender才会发送数据。默认16k linger.ms:如果迟迟没有达到batch.size,sender等待linger.ms设置时间之后,发送数据。单位:ms,默认0(没有延迟) acks设置: 0:不需要等待数据落盘应答;1:leader…

Java ---多线程(下)

(一)目录 线程的优先级 守护线程 线程同步 线程并发协作 主要内容 (二)线程的优先级 1 什么是线程的优先级 每一个线程都是有优先级的,我们可以为每个线程定义线程的优先级,但是这并不能保 证高优…

Anaconda下载与安装详解

文章目录 1 Anaconda1.1 简介1.2 下载安装1.3 配置环境变量1.4 下载配置1.4.1 conda配置1.4.1.1 修改conda下载源1.4.1.2 删除下载源1.4.1.3 包下载目录1.4.1.4 下载报错 1.4.2 pip配置1.4.2.1 配置源1.4.2.2 下载目录1.4.2.3 修改下载目录 1.5 修改虚拟环境地址1.5.1 通过配置…

【软件开发】Memcached(理论篇)

Memcached(理论篇) 1.Memcached 简介 Memcached 是一个开源的,支持高性能,高并发的分布式内存缓存系统,由 C 语言编写,总共 2000 多行代码。从软件名称上看,前 3 个字符 Mem 就是内存的意思&am…

quartz原理

1.如何实现任务 2.3个组件 3.工作原理 在Quartz中,有两类线程,Scheduler调度线程和任务执行线程,其中任务执行线程通常使用一个线程池维护一组线程。 Scheduler调度线程主要有两个:执行常规调度的线程,和执行misfir…