展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > mysql事务的含义是什么

mysql事务的含义是什么

mysql事务是指对数据库执行一批操作,在同一个事务当中,这些操作最终要么全部执行成功,要么全部失败,不会存在部分成功的情况;事务是一个原子操作,是一个最小执行单元,可以由一个或多个SQL语句组成。什么是事务?数据库中的事务是指对数据库执行一批操作,在同一个事务当中,这些操作最终要么全部执行成功,要么全部失败,不会存在部分成功的情况。事务是一个原子操作。是一个最小执行单元。可以由一个或多个SQL语句组成在同一个事务当中,所有的SQL语句都成功执行时,整个事务成功,有一个SQL语句执行失败,整个事务都执行失

本文目录

    mysql事务是指对数据库执行一批操作,在同一个事务当中,这些操作最终要么全部执行成功,要么全部失败,不会存在部分成功的情况;事务是一个原子操作,是一个最小执行单元,可以由一个或多个SQL语句组成。

    什么是事务?

    数据库中的事务是指对数据库执行一批操作,在同一个事务当中,这些操作最终要么全部执行成功,要么全部失败,不会存在部分成功的情况。

    • 事务是一个原子操作。是一个最小执行单元。可以由一个或多个SQL语句组成

    • 在同一个事务当中,所有的SQL语句都成功执行时,整 个事务成功,有一个SQL语句执行失败,整个事务都执行失败。

    举个例子:

    比如A用户给B用户转账100操作,过程如下:

    1. 从A账户扣100

    2. 给B账户加100

    如果在事务的支持下,上面最终只有2种结果:

    1. 操作成功:A账户减少100;B账户增加100

    2. 操作失败:A、B两个账户都没有发生变化

    如果没有事务的支持,可能出现错:A账户减少了100,此时系统挂了,导致B账户没有加上100,而A账户凭空少了100。

    事务的几个特性(ACID) -重点

    原子性(Atomicity)

    事务的整个过程如原子操作一样,最终要么全部成功,或者全部失败,这个原子性是从最终结果来看的,从最终结果来看这个过程是不可分割的。

    一致性(Consistency)

    一个事务必须使数据库从一个一致性状态变换到另一个一致性状态。

    首先回顾一下一致性的定义。所谓一致性,指的是数据处于一种有意义的状态,这种状态是语义上的而不是语法上的。最常见的例子是转帐。例如从帐户A转一笔钱到帐户B上,如果帐户A上的钱减少了,而帐户B上的钱却没有增加,那么我们认为此时数据处于不一致的状态。

    从这段话的理解来看,所谓一致性,即,从实际的业务逻辑上来说,最终结果是对的、是跟程序员的所期望的结果完全符合的

    隔离性(Isolation)

    一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

    • 这里先提一下事务的隔离级别:

      • 读未提交:read uncommitted

      • 读已提交:read committed

      • 可重复读:repeatable read

      • 串行化:serializable

    持久性(Durability)

    一个事务一旦提交,他对数据库中数据的改变就应该是永久性的。当事务提交之后,数据会持久化到硬盘,修改是永久性的。

    Mysql中事务操作

    mysql中事务默认是隐式事务,执行insert、update、delete操作的时候,数据库自动开启事务、提交或回滚事务。

    是否开启隐式事务是由变量autocommit控制的。

    所以事务分为隐式事务和显式事务。

    隐式事务

    事务自动开启、提交或回滚,比如insert、update、delete语句,事务的开启、提交或回滚由mysql内部自动控制的。

    查看变量autocommit是否开启了自动提交

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

    autocommit为ON表示开启了自动提交。

    显式事务

    事务需要手动开启、提交或回滚,由开发者自己控制。

    2种方式手动控制事务:

    方式1:

    语法:

    //设置不自动提交事务set autocommit=0;//执行事务操作commit|rollback;
    

    示例1:提交事务操作,如下:

    mysql> create table test1 (a int);Query OK, 0 rows affected (0.01 sec)mysql> select * from test1;Empty set (0.00 sec)mysql> set autocommit=0;Query OK, 0 rows affected (0.00 sec)mysql> insert into test1 values(1);Query OK, 1 row affected (0.00 sec)mysql> commit;Query OK, 0 rows affected (0.00 sec)mysql> select * from test1;+------+| a   |+------+|   1 |+------+1 row in set (0.00 sec)
    

    示例2:回滚事务操作,如下:

    mysql> set autocommit=0;Query OK, 0 rows affected (0.00 sec)mysql> insert into test1 values(2);Query OK, 1 row affected (0.00 sec)mysql> rollback;Query OK, 0 rows affected (0.00 sec)mysql> select * from test1;+------+| a   |+------+|   1 |+------+1 row in set (0.00 sec)
    

    可以看到上面数据回滚了。

    我们把autocommit还原回去:

    mysql> set autocommit=1;Query OK, 0 rows affected (0.00 sec)
    
    方式2:

    语法:

    start transaction;//开启事务//执行事务操作commit|rollback;
    

    示例1:提交事务操作,如下:

    mysql> select * from test1;+------+| a   |+------+|   1 |+------+1 row in set (0.00 sec)mysql> start transaction;Query OK, 0 rows affected (0.00 sec)mysql> insert into test1 values (2);Query OK, 1 row affected (0.00 sec)mysql> insert into test1 values (3);Query OK, 1 row affected (0.00 sec)mysql> commit;Query OK, 0 rows affected (0.00 sec)mysql> select * from test1;+------+| a   |+------+|   1 ||   2 ||   3 |+------+3 rows in set (0.00 sec)
    

    上面成功插入了2条数据。

    示例2:回滚事务操作,如下:

    mysql> select * from test1;+------+| a   |+------+|   1 ||   2 ||   3 |+------+3 rows in set (0.00 sec)mysql> start transaction;Query OK, 0 rows affected (0.00 sec)mysql> delete from test1;Query OK, 3 rows affected (0.00 sec)mysql> rollback;Query OK, 0 rows affected (0.00 sec)mysql> select * from test1;+------+| a   |+------+|   1 ||   2 ||   3 |+------+3 rows in set (0.00 sec)
    

    上面事务中我们删除了test1的数据,显示删除了3行,最后回滚了事务。

    savepoint关键字

    在事务中我们执行了一大批操作,可能我们只想回滚部分数据,怎么做呢?

    我们可以将一大批操作分为几个部分,然后指定回滚某个部分。可以使用savepoin来实现,效果如下:

    先清除test1表数据:

    mysql> delete from test1;Query OK, 3 rows affected (0.00 sec)mysql> select * from test1;Empty set (0.00 sec)
    

    演示savepoint效果,认真看:

    mysql> start transaction;Query OK, 0 rows affected (0.00 sec)mysql> insert into test1 values (1);Query OK, 1 row affected (0.00 sec)mysql> savepoint part1;//设置一个保存点Query OK, 0 rows affected (0.00 sec)mysql> insert into test1 values (2);Query OK, 1 row affected (0.00 sec)mysql> rollback to part1;//将savepint = part1的语句到当前语句之间所有的操作回滚Query OK, 0 rows affected (0.00 sec)mysql> commit;//提交事务Query OK, 0 rows affected (0.00 sec)mysql> select * from test1;+------+| a   |+------+|   1 |+------+1 row in set (0.00 sec)
    

    从上面可以看出,执行了2次插入操作,最后只插入了1条数据。

    savepoint需要结合rollback to sp1一起使用,可以将保存点sp1到rollback to之间的操作回滚掉。

    只读事务

    表示在事务中执行的是一些只读操作,如查询,但是不会做insert、update、delete操作,数据库内部对只读事务可能会有一些性能上的优化。

    用法如下:

    start transaction read only;
    

    示例:

    mysql> commit;Query OK, 0 rows affected (0.00 sec)mysql> start transaction read only;Query OK, 0 rows affected (0.00 sec)mysql> select * from test1;+------+| a   |+------+|   1 ||   1 |+------+2 rows in set (0.00 sec)mysql> delete from test1;ERROR 1792 (25006): Cannot execute statement in a READ ONLY transaction.mysql> commit;Query OK, 0 rows affected (0.00 sec)mysql> select * from test1;+------+| a   |+------+|   1 ||   1 |+------+2 rows in set (0.00 sec)
    

    只读事务中执行delete会报错。

    事务中的一些问题(重点)

    这些问题主要是基于数据在多个事务中的可见性来说的。也是并发事务产生的问题。

    更新丢失

    丢失更新就是两个不同的事务(或者Java程序线程)在某一时刻对同一数据进行读取后,先后进行修改。导致第一次操作数据丢失。

    「

    第一类丢失更新 :A,B 事务同时操作同一数据,A先对改数据进行了更改,B再次更改时失败然后回滚,把A更新的数据也回滚了。(事务撤销造成的撤销丢失)

    第二类丢失更新:A,B 事务同时操作同一数据,A先对改数据进行了更改,B再次更改并且提交,把A提交的数据给覆盖了。(事务提交造成的覆盖丢失)

    」

    脏读

    一个事务在执行的过程中读取到了其他事务还没有提交的数据。 这个还是比较好理解的。

    「

    两个事务同时操作同一数据,A事务对该数据进行了修改还没提交的时候,B事务访问了该条事务,并且使用了该数据,此时A事务回滚,那么B事务读到的就是脏数据。

    比如事务1,修改了某个数据 事务2,刚好访问了事务1修改后的数据

    此时事务1,回滚了操作 事务2,读到还是回滚前的数据

    」

    读已提交

    从字面上我们就可以理解,即一个事务操作过程中可以读取到其他事务已经提交的数据。

    事务中的每次读取操作,读取到的都是数据库中其他事务已提交的最新的数据(相当于当前读)

    不可重复读

    在同一事务中,多次读取同一数据返回的结果有所不同,换句话说,后续读取可以读到另一事务已提交的更新数据。相反,“可重复读” 在同一事务中多次读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据。

    「

    这种情况发生 在一个事务内多次读同一数据。A事务查询某条数据,该事务未结束时,B事务也访问同一数据并进行了修改。那么在A事务中的两 次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。

    事务1,查询某个数据 事务2,修改了某个数据,提交

    事务1,再次查询这个数据

    这样事务1两次查询的数据不一样,称为不可重复读

    」

    可重复读

    一个事务操作中对于一个读取操作不管多少次,读取到的结果都是一样的。

    幻读

    脏读、不可重复读、可重复读、幻读,其中最难理解的是幻读

    以mysql为例:

    • 幻读现象例子:

      • 可重复读模式下,比如有个用户表,手机号码为主键,有两个事物进行如下操作

      • 事务A操作如下: 1、打开事务 2、查询号码为X的记录,不存在 3、插入号码为X的数据,插入报错(为什么会报错,先向下看) 4、查询号码为X的记录,发现还是不存在(由于是可重复读,所以读取记录X还是不存在的)

      • 事物B操作:在事务A第2步操作时插入了一条X的记录,所以会导致A中第3步插入报错(违反了唯一约束)

      • 上面操作对A来说就像发生了幻觉一样,明明查询X(A中第二步、第四步)不存在,但却无法插入成功

      • 幻读可以这么理解:事务中后面的操作(插入号码X)需要上面的读取操作(查询号码X的记录)提供支持,但读取操作却不能支持下面的操作时产生的错误,就像发生了幻觉一样。

    • 看第二种解释:

      • 事务A在操作一堆数据的时候,事务B插入了一条数据,A事务再次(第二次)查询,发现多了一条数据,像是幻觉。与不可重复读类似,不同的是一个是修改删除操作,一个是新增操作。

    如果还是理解不了的,继续向下看,后面后详细的演示。

    事务的隔离级别

    当多个事务同时进行的时候,如何确保当前事务中数据的正确性,比如A、B两个事物同时进行的时候,A是否可以看到B已提交的数据或者B未提交的数据,这个需要依靠事务的隔离级别来保证,不同的隔离级别中所产生的效果是不一样的。

    事务隔离级别主要是解决了上面多个事务之间数据可见性及数据正确性的问题。(或者说为了解决并发控制可能产生的异常问题,数据库定义了四种事务的隔离级别)

    隔离级别分为4种:

    1. 读未提交:READ-UNCOMMITTED

    2. 读已提交:READ-COMMITTED

    3. 可重复读:REPEATABLE-READ

    4. 串行:SERIALIZABLE

    上面4中隔离级别越来越强,会导致数据库的并发性也越来越低。

    查看隔离级别

    mysql> show variables like 'transaction_isolation';+-----------------------+----------------+| Variable_name     | Value      |+-----------------------+----------------+| transaction_isolation | READ-COMMITTED |+-----------------------+----------------+1 row in set, 1 warning (0.00 sec)
    

    隔离级别的设置

    分2步骤,修改文件、重启mysql,如下:

    修改mysql中的my.init文件,我们将隔离级别设置为:READ-UNCOMMITTED,如下:

    # 隔离级别设置,READ-UNCOMMITTED读未提交,READ-COMMITTED读已提交,REPEATABLE-READ可重复读,SERIALIZABLE串行transaction-isolation=READ-UNCOMMITTED
    

    以管理员身份打开cmd窗口,重启mysql,如下:

    C:\Windows\system32>net stop mysql
    mysql 服务正在停止..mysql 服务已成功停止。
    
    C:\Windows\system32>net start mysql
    mysql 服务正在启动 .mysql 服务已经启动成功。
    

    各种隔离级别中会出现的问题

    隔离级别脏读可能性不可重复读可能性幻读可能性
    READ-UNCOMMITTED有有有
    READ-COMMITTED无有有
    REPEATABLE-READ无无有
    SERIALIZABLE无无无

    下面我们来演示一下,各种隔离级别中可见性的问题,开启两个窗口,叫做A、B窗口,两个窗口中登录mysql。

    READ-UNCOMMITTED:读未提交

    将隔离级别置为READ-UNCOMMITTED:

    # 隔离级别设置,READ-UNCOMMITTED读未提交,READ-COMMITTED读已提交,REPEATABLE-READ可重复读,SERIALIZABLE串行transaction-isolation=READ-UNCOMMITTED
    

    重启mysql:

    C:\Windows\system32>net stop mysql
    mysql 服务正在停止..mysql 服务已成功停止。
    
    C:\Windows\system32>net start mysql
    mysql 服务正在启动 .mysql 服务已经启动成功。
    

    查看隔离级别:

    mysql> show variables like 'transaction_isolation';+-----------------------+----------------+| Variable_name     | Value      |+-----------------------+----------------+| transaction_isolation | READ-UNCOMMITTED |+-----------------------+----------------+1 row in set, 1 warning (0.00 sec)
    

    先清空test1表数据:

    delete from test1;select * from test1;
    

    按时间顺序在2个窗口中执行下面操作:

    时间窗口A窗口B
    T1start transaction;
    T2select * from test1;
    T3
    start transaction;
    T4
    insert into test1 values (1);
    T5
    select * from test1;
    T6select * from test1;
    T7
    commit;
    T8commit;

    A窗口如下:

    mysql> start transaction;Query OK, 0 rows affected (0.00 sec)mysql> select * from test1;Empty set (0.00 sec)mysql> select * from test1;+------+| a   |+------+|   1 |+------+1 row in set (0.00 sec)mysql> commit;Query OK, 0 rows affected (0.00 sec)
    

    B窗口如下:

    mysql> start transaction;Query OK, 0 rows affected (0.00 sec)mysql> insert into test1 values (1);Query OK, 1 row affected (0.00 sec)mysql> select * from test1;+------+| a   |+------+|   1 |+------+1 row in set (0.00 sec)mysql> commit;Query OK, 0 rows affected (0.00 sec)
    

    看一下:

    T2-A:无数据,T6-A:有数据,T6时刻B还未提交,此时A已经看到了B插入的数据,说明出现了脏读。

    T2-A:无数据,T6-A:有数据,查询到的结果不一样,说明不可重复读。

    结论:读未提交情况下,可以读取到其他事务还未提交的数据,多次读取结果不一样,出现了脏读、不可重复读、幻读

    READ-COMMITTED:读已提交

    将隔离级别置为READ-COMMITTED

    # 隔离级别设置,READ-UNCOMMITTED读未提交,READ-COMMITTED读已提交,REPEATABLE-READ可重复读,SERIALIZABLE串行transaction-isolation=READ-COMMITTED
    

    重启mysql:

    C:\Windows\system32>net stop mysql
    mysql 服务正在停止..mysql 服务已成功停止。
    
    C:\Windows\system32>net start mysql
    mysql 服务正在启动 .mysql 服务已经启动成功。
    

    查看隔离级别:

    mysql> show variables like 'transaction_isolation';+-----------------------+----------------+| Variable_name     | Value      |+-----------------------+----------------+| transaction_isolation | READ-COMMITTED |+-----------------------+----------------+1 row in set, 1 warning (0.00 sec)
    

    先清空test1表数据:

    delete from test1;select * from test1;
    

    按时间顺序在2个窗口中执行下面操作:

    时间窗口A窗口B
    T1start transaction;
    T2select * from test1;
    T3
    start transaction;
    T4
    insert into test1 values (1);
    T5
    select * from test1;
    T6select * from test1;
    T7
    commit;
    T8select * from test1;
    T9commit;

    A窗口如下:

    mysql> start transaction;Query OK, 0 rows affected (0.00 sec)mysql> select * from test1;Empty set (0.00 sec)mysql> select * from test1;Empty set (0.00 sec)mysql> select * from test1;+------+| a   |+------+|   1 |+------+1 row in set (0.00 sec)mysql> commit;Query OK, 0 rows affected (0.00 sec)
    

    B窗口如下:

    mysql> start transaction;Query OK, 0 rows affected (0.00 sec)mysql> insert into test1 values (1);Query OK, 1 row affected (0.00 sec)mysql> select * from test1;+------+| a   |+------+|   1 |+------+1 row in set (0.00 sec)mysql> commit;Query OK, 0 rows affected (0.00 sec)
    

    看一下:

    T5-B:有数据,T6-A窗口:无数据,A看不到B的数据,说明没有脏读。

    T6-A窗口:无数据,T8-A:看到了B插入的数据,此时B已经提交了,A看到了B已提交的数据,说明可以读取到已提交的数据。

    T2-A、T6-A:无数据,T8-A:有数据,多次读取结果不一样,说明不可重复读。

    结论:读已提交情况下,无法读取到其他事务还未提交的数据,可以读取到其他事务已经提交的数据,多次读取结果不一样,未出现脏读,出现了读已提交、不可重复读、幻读

    REPEATABLE-READ:可重复读

    将隔离级别置为REPEATABLE-READ

    # 隔离级别设置,READ-UNCOMMITTED读未提交,READ-COMMITTED读已提交,REPEATABLE-READ可重复读,SERIALIZABLE串行transaction-isolation=REPEATABLE-READ
    

    重启mysql:

    C:\Windows\system32>net stop mysql
    mysql 服务正在停止..mysql 服务已成功停止。
    
    C:\Windows\system32>net start mysql
    mysql 服务正在启动 .mysql 服务已经启动成功。
    

    查看隔离级别:

    mysql> show variables like 'transaction_isolation';+-----------------------+----------------+| Variable_name     | Value      |+-----------------------+----------------+| transaction_isolation | REPEATABLE-READ |+-----------------------+----------------+1 row in set, 1 warning (0.00 sec)
    

    先清空test1表数据:

    delete from test1;select * from test1;
    

    按时间顺序在2个窗口中执行下面操作:

    时间窗口A窗口B
    T1start transaction;
    T2select * from test1;
    T3
    start transaction;
    T4
    insert into test1 values (1);
    T5
    select * from test1;
    T6select * from test1;
    T7
    commit;
    T8select * from test1;
    T9commit;
    T10select * from test1;

    A窗口如下:

    mysql> start transaction;Query OK, 0 rows affected (0.00 sec)mysql> select * from test1;Empty set (0.00 sec)mysql> select * from test1;Empty set (0.00 sec)mysql> select * from test1;Empty set (0.00 sec)mysql> commit;Query OK, 0 rows affected (0.00 sec)mysql> select * from test1;+------+| a   |+------+|   1 ||   1 |+------+2 rows in set (0.00 sec)
    

    B窗口如下:

    mysql> start transaction;Query OK, 0 rows affected (0.00 sec)mysql> insert into test1 values (1);Query OK, 1 row affected (0.00 sec)mysql> select * from test1;+------+| a   |+------+|   1 ||   1 |+------+2 rows in set (0.00 sec)mysql> commit;Query OK, 0 rows affected (0.00 sec)
    

    看一下:

    T2-A、T6-A窗口:无数据,T5-B:有数据,A看不到B的数据,说明没有脏读。

    T8-A:无数据,此时B已经提交了,A看不到B已提交的数据,A中3次读的结果一样都是没有数据的,说明可重复读。

    结论:可重复读情况下,未出现脏读,未读取到其他事务已提交的数据,多次读取结果一致,即可重复读。

    幻读演示

    将隔离级别置为REPEATABLE-READ

    # 隔离级别设置,READ-UNCOMMITTED读未提交,READ-COMMITTED读已提交,REPEATABLE-READ可重复读,SERIALIZABLE串行transaction-isolation=REPEATABLE-READ
    

    重启mysql:

    C:\Windows\system32>net stop mysql
    mysql 服务正在停止..mysql 服务已成功停止。
    
    C:\Windows\system32>net start mysql
    mysql 服务正在启动 .mysql 服务已经启动成功。
    

    查看隔离级别:

    mysql> show variables like 'transaction_isolation';+-----------------------+----------------+| Variable_name     | Value      |+-----------------------+----------------+| transaction_isolation | REPEATABLE-READ |+-----------------------+----------------+1 row in set, 1 warning (0.00 sec)
    

    准备数据:

    mysql> create table t_user(id int primary key,name varchar(16) unique key);Query OK, 0 rows affected (0.01 sec)mysql> insert into t_user values (1,'路人甲Java'),(2,'路人甲Java');ERROR 1062 (23000): Duplicate entry '路人甲Java' ***\*for\**** key 'name'mysql> select * from t_user;Empty set (0.00 sec)
    

    上面我们创建t_user表,name添加了唯一约束,表示name不能重复,否则报错。

    按时间顺序在2个窗口中执行下面操作:

    时间窗口A窗口B
    T1start transaction;
    T2
    start transaction;
    T3
    – 插入路人甲Java
    insert into t_user values (1,‘路人甲Java’);
    T4
    select * from t_user;
    T5– 查看路人甲Java是否存在
    select * from t_user where name=‘路人甲Java’;

    T6
    commit;
    T7– 插入路人甲Java
    insert into t_user values (2,‘路人甲Java’);

    T8– 查看路人甲Java是否存在
    select * from t_user where name=‘路人甲Java’;

    T9commit;

    A窗口如下:

    mysql> start transaction;Query OK, 0 rows affected (0.00 sec)mysql> select * from t_user where name='路人甲Java';Empty set (0.00 sec)mysql> insert into t_user values (2,'路人甲Java');ERROR 1062 (23000): Duplicate entry '路人甲Java' ***\*for\**** key 'name'mysql> select * from t_user where name='路人甲Java';Empty set (0.00 sec)mysql> commit;Query OK, 0 rows affected (0.00 sec)
    

    B窗口如下:

    mysql> start transaction;Query OK, 0 rows affected (0.00 sec)mysql> insert into t_user values (1,'路人甲Java');Query OK, 1 row affected (0.00 sec)mysql> select * from t_user;+----+---------------+| id | name      |+----+---------------+|  1 | 路人甲Java   |+----+---------------+1 row in set (0.00 sec)mysql> commit;Query OK, 0 rows affected (0.00 sec)
    

    看一下:

    A想插入数据路人甲Java,插入之前先查询了一下(T5时刻)该用户是否存在,发现不存在,然后在T7时刻执行插入,报错了,报数据已经存在了,因为T6时刻B已经插入了路人甲Java。

    然后A有点郁闷,刚才查的时候不存在的,然后A不相信自己的眼睛,又去查一次(T8时刻),发现路人甲Java还是不存在的。

    此时A心里想:数据明明不存在啊,为什么无法插入呢?这不是懵逼了么,A觉得如同发生了幻觉一样。

    SERIALIZABLE:串行

    SERIALIZABLE会让并发的事务串行执行(多个事务之间读写、写读、写写会产生互斥,效果就是串行执行,多个事务之间的读读不会产生互斥)。

    读写互斥:事务A中先读取操作,事务B发起写入操作,事务A中的读取会导致事务B中的写入处于等待状态,直到A事务完成为止。

    表示我开启一个事务,为了保证事务中不会出现上面说的问题(脏读、不可重复读、读已提交、幻读),那么我读取的时候,其他事务有修改数据的操作需要排队等待,等待我读取完成之后,他们才可以继续。

    写读、写写也是互斥的,读写互斥类似。

    这个类似于java中的java.util.concurrent.lock.ReentrantReadWriteLock类产生的效果。

    下面演示读写互斥的效果。

    将隔离级别置为SERIALIZABLE

    # 隔离级别设置,READ-UNCOMMITTED读未提交,READ-COMMITTED读已提交,REPEATABLE-READ可重复读,SERIALIZABLE串行transaction-isolation=SERIALIZABLE
    

    重启mysql:

    C:\Windows\system32>net stop mysql
    mysql 服务正在停止..mysql 服务已成功停止。
    
    C:\Windows\system32>net start mysql
    mysql 服务正在启动 .mysql 服务已经启动成功。
    

    查看隔离级别:

    mysql> show variables like 'transaction_isolation';+-----------------------+--------------+| Variable_name     | Value     |+-----------------------+--------------+| transaction_isolation | SERIALIZABLE |+-----------------------+--------------+1 row in set, 1 warning (0.00 sec)
    

    先清空test1表数据:

    delete from test1;select * from test1;
    

    按时间顺序在2个窗口中执行下面操作:

    时间窗口A窗口B
    T1start transaction;
    T2select * from test1;
    T3
    start transaction;
    T4
    insert into test1 values (1);
    T5commit;
    T6
    commit;

    按时间顺序运行上面的命令,会发现T4-B这样会被阻塞,直到T5-A执行完毕。

    上面这个演示的是读写互斥产生的效果,大家可以自己去写一下写读、写写互斥的效果。

    可以看出来,事务只能串行执行了。串行情况下不存在脏读、不可重复读、幻读的问题了。

    小结

    • 读未提交( Read Uncommitted )

      • 读未提交是隔离级别最低的一种事务级别。在这种隔离级别下,一个事务会读到另一个事务更新后但未提交的数据,如果另一个事务回滚,那么当前事务读到的数据就是脏数据,这就是脏读(Dirty Read)。

    • 读已提交( Read Committed )

      • 在 Read Committed 隔离级别下,一个事务可能会遇到不可重复读(Non Repeatable Read)的问题。不可重复读是指,在一个事务内,多次读同一数据,在这个事务还没有结束时,如果另一个事务恰好修改了这个数据,那么,在第一个事务中,两次读取的数据就可能不一致。

    • 可重复读( Repeatable Read )

      • 在Repeatable Read隔离级别下,一个事务可能会遇到幻读(Phantom Read)的问题。幻读是指,在一个事务中,第一次查询某条记录,发现没有,但是,当试图更新这条不存在的记录时,竟然能成功,并且,再次读取同一条记录,它就神奇地出现了。幻读就是没有读到的记录,以为不存在,但其实是可以更新成功的,并且,更新成功后,再次读取,就出现了。

    • 可串行化( Serializable )

      • Serializable 是最严格的隔离级别。在Serializable隔离级别下,所有事务按照次序依次执行,因此,脏读、不可重复读、幻读都不会出现。

      • 虽然 Serializable 隔离级别下的事务具有最高的安全性,但是,由于事务是串行执行,所以效率会大大下降,应用程序的性能会急剧降低。如果没有特别重要的情景,一般都不会使用Serializable隔离级别。

    默认隔离级别:如果没有指定隔离级别,数据库就会使用默认的隔离级别。在MySQL中,如果使用 InnoDB,默认的隔离级别是Repeatable Read。

    关于隔离级别的选择

    1. 需要对各种隔离级别产生的现象非常了解,然后选择的时候才能游刃有余

    2. 隔离级别越高,并发性也低,比如最高级别SERIALIZABLE会让事物串行执行,并发操作变成串行了,会导致系统性能直接降低。

    3. 具体选择哪种需要结合具体的业务来选择。

    4. 读已提交(READ-COMMITTED)通常用的比较多。

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 MySQL
    相关文章 更多
    精品专题 更多
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    IOS软件

    正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

    AI

    正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

    Mac软件 更多
    Aperty macOS版
    Aperty macOS版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw macOS版
    AionClaw macOS版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy macOS版
    Loomy macOS版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

    AirBuddy 3 macOS版
    AirBuddy 3 macOS版

    AirBuddy 3 是面向 macOS 的蓝牙外设增强工具,可集中查看 AirPods、Beats 与苹果设备电量,提供快速连接、播放控制、电量提醒、桌面小组件和多台 Mac 外设接力等功能。

    AirServer macOS版
    AirServer macOS版

    AirServer macOS版可把 Mac 转换为无线投屏接收端,通过 AirPlay 或 Google Cast 接收手机、平板和电脑画面,并支持多设备同时连接、高清镜像及会话录制,适合家庭娱乐、课堂教学、会议演示和应用展示。

    AnyDesk macOS版
    AnyDesk macOS版

    AnyDesk macOS版是一款适用于远程办公、设备维护和客户支持的远程桌面工具,可连接并操作异地计算机,支持文件传输、无人值守访问、会话权限控制及跨平台协作。

    WINDOWS 更多
    讯飞绘文 网页版
    讯飞绘文 网页版

    讯飞绘文网页版是科大讯飞推出的AI图文创作与内容运营工具,覆盖热点选题、文章生成、稿件校对、智能配图、排版发布和数据复盘等环节,适合自媒体创作者及内容团队在线使用。

    Maya(Autodesk Maya) Windows版
    Maya(Autodesk Maya) Windows版

    Autodesk Maya 是面向影视、电视、动画和游戏行业的专业三维制作软件,集多边形与 NURBS 建模、角色绑定、关键帧和动作捕捉动画、Bifrost 特效模拟、材质开发及 Arnold 渲染于一体,

    Aperty Windows版
    Aperty Windows版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw Windows版
    AionClaw Windows版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy Windows版
    Loomy Windows版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

    AirServer Windows版
    AirServer Windows版

    AirServer Windows版可把电脑变成AirPlay、Google Cast和Miracast无线投屏接收端,适合会议演示、课堂教学及家庭大屏分享。发送设备通常无需另装客户端,并可同时接收和智能排列多个镜像会话。