MySQL事务和隔离级别

  • MySQL基础架构

  • 连接管理器:接收请求接收请求-->创建线程-->认证用户-->建立安全连接;

  • 优化器的缺陷:

    • 有时候执行的优化并不一定是最优化的,如果有最优化的方式,直接进行指定,不建议进行优化,省去优化器优化的开销;
    • 优化器优化的过程并不会考虑存储引擎的不同;
  • 不是所有的结果都是需要进行缓存的,非确定性结果就不应该进行缓存,具有实时性要求的,不应该进行缓存;

  • 并发控制的一种原理,每个用户操作访问的都不是源数据,而是数据的快照,最后完成快照恢复,这种机制成为MVCC,也就是多版本并发访问控制机制,

  • 不能够缓存的例如当前时间,这种结果是非确定性结果;
    这里写图片描述

  • 对于多版本并发控制依赖的手段:

    • 锁机制:一个事务可能在启动事务时,长时间得不到锁,出现饥饿现象;还有可能出现死锁状况,如果出现死锁,事务调度,就应该控制事务进行回退;
    • 时间戳;
    • 多版本和快照隔离
  • 简单的锁控制机制:

    • 锁是最简单的并发机制控制;
    • 读锁是共享锁;
    • 写锁是独占锁;
  • 表锁:锁定一张表;

  • 页锁:锁定数据页面,数据页面可能包含多个行;

  • 行锁:锁定某一个行;

  • MySQL服务器仅仅支持表级别的锁,行锁需要由存储引擎完成,存储引擎都有自己的锁策略,很少需要手动的在服务器上面施加锁;

  • LOCK_TABLE
    这里写图片描述

  • 手动施加读锁

mysql> LOCK TABLES tutors read;
Query OK, 0 rows affected (0.00 sec)
  • 在另一个会话中开始进行查询,数据查询是允许的;
mysql> SELECT * FROM tutors;
+-----+--------------+--------+------+
| TID | Tname        | Gender | Age  |
+-----+--------------+--------+------+
|   1 | HongQigong   | M      |   93 |
|   2 | HuangYaoshi  | M      |   63 |
|   3 | Miejueshitai | F      |   72 |
|   4 | OuYangfeng   | M      |   76 |
|   5 | YiDeng       | M      |   90 |
|   6 | YuCanghai    | M      |   56 |
|   7 | Jinlunfawang | M      |   67 |
|   8 | HuYidao      | M      |   42 |
|   9 | NingZhongze  | F      |   49 |
|  10 | DingDian     | M      |   25 |
|  11 | HuFei        | M      |   31 |
|  12 | ZhangWuji    | M      |   20 |
|  13 | Xuzhu        | M      |   26 |
|  14 | LingHuchong  | M      |   22 |
+-----+--------------+--------+------+
14 rows in set (0.00 sec)
  • 插入数据是不能够完成的,陷入等待释放读锁
    这里写图片描述
  • 释放读锁,数据插入立即完成
    这里写图片描述

这里写图片描述

  • 事务的特性

  • 需要满足ACID特性,也就是满足

    • 原子性:Automicity事务涉及的多个执行语句,要么同时完成,要么同时不完成,必须当作一个整体来看待;
    • 一致性:Consistency:一致性,事务执行结束之后,数据库的执行状态是没有改变的;
    • 隔离性:Isolation:隔离性,用于保证各个事务之间彼此不被影响,通过各个之间的事务调度执行,各个事务之间降低彼此之间的影响;
    • 持久性:Durability持久性,一旦事务成功完成,都必须保证这个事务是稳定的,系统出现必须保证任何故障下都不会引起事务表示出不一致性;
      • 1.事务提交之前的数据应该写入永久性存储,效率低下;
      • 2.结合事务日志,事务日志是保存在永久性存储设备上面的;
      • 3.事务日志产生的是顺序IO,在存储的时候是连续的,数据文件是随机IO;
  • MySQL的事务引擎是交给存储引擎来控制的,InnoDB是支持事务的;

  • 事务日志:

  • 重做日志Redo:表示按照日志里面记录的信息,将需要的重新完成一遍;

  • 撤销日志undo log: 表示撤销日志纪录中已经完成的操作;

  • 为了结合事务日志的处理机制,MySQL的数据处理都是在内存中完成,并且将操作的记录写在事务日志中,然后将事务日志按照里面的记录在磁盘上面对数据进行操作;

  • 对于数据的增删查改,首先在内存中完成,然后写入事务日志中,通过事务日志的重做日志在执行一遍,然后写入实际的数据文件中去,写在日志中,要快的多,日志中记录的仅仅是操作,而不是数据文件本身;

    • 对于完成提交的事务,如果在写入磁盘的过程中崩溃,那么需要重做日志进行重做;
    • 对于没有完成的事务,再写入次怕的过程中崩溃,那么执行撤销日志,撤销执行;
    • 日志文件应该尽量小,但是应该存在不止一个,通常使用是日志组来完成的;
  • 事务日志文件通常不是一个,而是多个,称为日志组,一个用于进行写入,另一个马上在磁盘上面的重做操作,通常是交替进行;

  • 事务日志和数据文件应该在不同的设备上面;

  • 事务的状态

  • ACTIVE:活动的;

  • 部分提交:最后一条语句正在执行;

  • 失败的:事务正常提交,但是提交没有完成;

  • 终止的:没有提交,就提前结束的;

  • 提交的:成功提交,并且成功执行的,事务一旦提交,就没有办法撤销,如果需要撤销,就只能够通过补偿事务来完成;

  • 事务允许进行并发执行,并且通过调度来保证事务的特性:

  • 可恢复调度:任何两个事务的交叉执行,都不会导致另外一个事务状态的改变,会滚的时候可能存在影响;

  • 无级联调度: 为了避免事务在会滚的时候产生影响;

  • 事务的隔离级别

  • 这是在启动两个事务的情况下,根据不同的隔离级别,出现不同的结果;

  • 隔离级别越低,事务存在干扰的可能性越大

  • read uncommitted:读未提交, 别人操作,可以立即看见,隔离级别最低;

  • read commited:读提交,表示别人提交之后,可以立即看到,会出现幻读;

  • repeatabled read:表示可重读,表示无论是否进行提交,从第一次看到直到事务提交之前都是什么样;MySQL默认是这样的;

  • serialiable:表示按照串行进行执行;

  • 隔离级别越高,并发能力越低,降低隔离级别可以提高MySQL性能;

  • 查看默认的隔离级别

mysql> SHOW GLOBAL VARIABLES LIKE '%iso%';
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| tx_isolation  | REPEATABLE-READ |
+---------------+-----------------+
1 row in set (0.00 sec)
  • 事务的隔离级别
mysql> SET tx_isolation='READ-UNCOMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @@tx_isolation;
+------------------+
| @@tx_isolation   |
+------------------+
| READ-UNCOMMITTED |
+------------------+
1 row in set (0.00 sec)
  • 事务的操作
  • 启动一个事务
mysql> START TRANSACTION;
  • 执行SQL语句
  • 然后进行提交事务,
mysql> commit;
  • 执行commit之后,事务就不能够撤销的;
  • 在执行SQL语句的时候,如果放弃事务的执行,可以使用ROLLBACK来放弃事务的执行;
  • 启动一个事务
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM tutors;
+-----+--------------+--------+------+
| TID | Tname        | Gender | Age  |
+-----+--------------+--------+------+
|   1 | HongQigong   | M      |   93 |
|   2 | HuangYaoshi  | M      |   63 |
|   3 | Miejueshitai | F      |   72 |
|   4 | OuYangfeng   | M      |   76 |
|   5 | YiDeng       | M      |   90 |
|   6 | YuCanghai    | M      |   56 |
|   7 | Jinlunfawang | M      |   67 |
|   8 | HuYidao      | M      |   42 |
|   9 | NingZhongze  | F      |   49 |
|  10 | DingDian     | M      |   25 |
|  11 | HuFei        | M      |   31 |
|  12 | ZhangWuji    | M      |   20 |
|  13 | Xuzhu        | M      |   26 |
|  14 | LingHuchong  | M      |   22 |
|  15 | jerry        | M      |   50 |
+-----+--------------+--------+------+
15 rows in set (0.00 sec)
  • 接下来执行一些操作
mysql> DELETE FROM tutors WHERE Tname LIKE 'je%';
Query OK, 0 rows affected (0.00 sec)
  • 查看数据,已经被删除,但是没有同步到磁盘上面;
  • 如果不想进行删除,不要进行commit而是进行ROLLBACK进行事务的回滚操作
mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)
  • auto_commit:表示事务的自动提交
mysql>  SELECT @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            1 |
+--------------+
1 row in set (0.00 sec)
  • 如果没有明确的启动事务,就能够实现自动提交的,不能够执行ROLLBACK的,建议明确使用事务,并且关闭自动提交,否则IO导致性能降低;
  • 关闭这个变量之后,就可以进行回滚操作了,但是对于确定的操作,需要执行commit操作
mysql> SET autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> DELETE FROM tutors WHERE Tname='jerry';
Query OK, 1 row affected (0.00 sec)

mysql> ROLLBACK;
Query OK, 0 rows affected (0.01 sec)
  • 事务的SAVEPOINT:
  • 在进行事务里面的大量语句操作时,设置保存点,在进行语句撤销时,一次撤销到某个保存点,而不是撤销完成所有的语句;
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> DELETE FROM tutors WHERE TID=10;
Query OK, 1 row affected (0.00 sec)

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

mysql> DELETE FROM tutors WHERE TID=9;
Query OK, 1 row affected (0.00 sec)

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

mysql> DELETE FROM tutors WHERE TID=8;
Query OK, 1 row affected (0.00 sec)

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

mysql> DELETE FROM tutors WHERE TID=7;
Query OK, 1 row affected (0.00 sec)

mysql> SAVEPOINT ae;
Query OK, 0 rows affected (0.00 sec)
  • 执行完上述操作之后
    这里写图片描述
  • 然后进行回滚到某个SAVEPOINT;
    这里写图片描述
  • 事务的隔离级别对于事务的影响
  • 启动两个MySQL会话,并且设定默认的隔离级别为下面的几种:
  • 验证READ_UNCOMMITTED:
  • 会话1:
mysql> SET tx_isolation='READ-UNCOMMITTED';
Query OK, 0 rows affected (0.00 sec)
  • 会话2:
mysql> SET tx_isolation='READ-UNCOMMITTED';
Query OK, 0 rows affected (0.00 sec)
  • 交叉启动事务
  • 会话1
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.02 sec)

  • 会话2
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
  • 修改某个用户的年龄
  • 在会话1里面修改HuFei的年龄
mysql> UPDATE tutors SET Age=50 WHERE TID=12;
Query OK, 1 row affected (0.05 sec)
Rows matched: 1  Changed: 1  Warnings: 0
  • 然后再会话2里面进行查看,是可以查看到修改的内容的
    这里写图片描述
  • 如果会话1执行了,撤销操作
mysql> ROLLBACK;
Query OK, 0 rows affected (0.03 sec)
  • 那么会话2就会就会修为原来的数据
    这里写图片描述
  • 接下来修改级别为READ-COMMITTED;
  • 会话1
mysql>  SET tx_isolation='READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
  • 会话2:
mysql> SET tx_isolation='READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
  • 接下来修改数据
  • 会话1
mysql> UPDATE tutors SET Age=50 WHERE TID=12;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
  • 会话2查看数据,TID12的并没有进行修改
    这里写图片描述
  • 会话1在进行提交之后,这个值就会发生改变
mysql> COMMIT;
Query OK, 0 rows affected (0.25 sec)
  • 会话2查看的数据已经发生改变
    这里写图片描述
  • 提交事务
  • 会话1
mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec
  • 会话2,进行提交
mysql> COMMIT;
Query OK, 0 rows affected (0.25 sec)
  • 修改事务隔离级别为REPEATABLE-READ,并且启动事务
  • 会话1
mysql> SET tx_isolation='REPEATABLE-READ';
Query OK, 0 rows affected (0.00 sec)

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.01 sec)
  • 会话2,同时修改事务隔离级别,并且启动事务
mysql> SET tx_isolation='REPEATABLE-READ';
Query OK, 0 rows affected (0.00 sec)

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
  • 接下来进行数据的修改
  • 会话1
mysql> UPDATE tutors SET Age=100 WHERE TID=12;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

这里写图片描述

  • 会话2,查看数据是否发生改变
    这里写图片描述
  • 会话1提交事务,会话2上面查询的数据仍然没有改变
mysql> COMMIT;
Query OK, 0 rows affected (0.79 sec)
  • 会话2上面的数据,没有发生改变;
    这里写图片描述

  • 会话2进行事务的提交,查看数据,已经进行更新
    这里写图片描述

  • 验证SERIALIZALE

  • 会话1修改,日志的隔离级别为SERIALIZABLE,并且启动事务

mysql> SET tx_isolation='SERIALIZABLE';
Query OK, 0 rows affected (0.00 sec)

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
  • 会话2同样进行修改,并且启动日志
mysql> SET tx_isolation='SERIALIZABLE';
Query OK, 0 rows affected (0.00 sec)

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
  • 在会话1上面进行修改数据
mysql> UPDATE tutors SET Age=10 WHERE TID=12;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
  • 会话2上面是查询不到变化的信息的,因为不允许两个事务同时操作同一个数据
mysql> SELECT * FROM tutors;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
  • 在会话1上面提交数据
mysql> COMMIT;
Query OK, 0 rows affected (0.03 sec)
  • 会话1的数据修改完成
    这里写图片描述
  • 会话2的查看就可以正常完成,并且可以得到信息
    这里写图片描述
  • 会话2提交数据之后,得到信息是不会发生改变的
    这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值