[关闭]
@nalan90 2017-12-19T18:03:41.000000Z 字数 8655 阅读 989

MySQL事务

MySQL


事务的基本概念

事务(Transaction)是并发控制的基本单位。所谓的事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。例如,银行转账工作:从一个账号扣款并使另一个账号增款,这两个操作要么都执行,要么都不执行。所以,应该把它们看成一个事务。事务是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据一致性。


事务的基本特征


数据库的隔离现象

隔离现象 描述
脏读(Dirty Read) 事务B读到事务A尚未提交的数据变更
不可重复读(NonRepeatable Read) 事务B后两次读取一条记录之间被事务A修改并提交,于是事务B读到了不一样的结果
幻读(Phantom Read) 事务B按条件匹配到了若干行记录并修改。但是由于修改过程中事务A新插入了符合条件的记录,导致B更新完成后发现仍有符合条件却未被更新的记录

MYSQL的事务隔离级别


事务的持久化的实现

image_1arn1ukjrdkn1uc6c851u9p38l.png-143.1kB


事务相关命令


相关参数说明

  1. MySQL中存在两个变量对事务的影响
    • autocommit(是否自动提交事务)
    • tx_isolation(事务的隔离等级)

  2. (autocommit)是否自动提交

    1. mysql> show global variables like 'autocommit';
    2. +---------------+-------+
    3. | Variable_name | Value |
    4. +---------------+-------+
    5. | autocommit | ON |
    6. +---------------+-------+
    7. 1 row in set (0.01 sec)

    实例如下:

    1. SESSION 1:
    2. 创建一张新表,并插入一条记录
    3. mysql> create table t(id int ,var int ,foo int);
    4. Query OK, 0 rows affected (0.02 sec)
    5. mysql> desc t;
    6. +-------+---------+------+-----+---------+-------+
    7. | Field | Type | Null | Key | Default | Extra |
    8. +-------+---------+------+-----+---------+-------+
    9. | id | int(11) | YES | | NULL | |
    10. | var | int(11) | YES | | NULL | |
    11. | foo | int(11) | YES | | NULL | |
    12. +-------+---------+------+-----+---------+-------+
    13. 3 rows in set (0.01 sec)
    14. mysql> select * from t;
    15. Empty set (0.00 sec)
    16. mysql> insert into t values(1,1,1);
    17. Query OK, 1 row affected (0.00 sec)
    18. mysql> select * from t;
    19. +------+------+------+
    20. | id | var | foo |
    21. +------+------+------+
    22. | 1 | 1 | 1 |
    23. +------+------+------+
    24. 1 row in set (0.00 sec)
    25. SESSION 2:
    26. 查看记录
    27. mysql> select * from t;
    28. +------+------+------+
    29. | id | var | foo |
    30. +------+------+------+
    31. | 1 | 1 | 1 |
    32. +------+------+------+
    33. 1 row in set (0.00 sec)

    关闭自动提交,执行如上操作,观察两个session的数据

    1. SESSION 1
    2. mysql> set global autocommit=0;
    3. Query OK, 0 rows affected (0.00 sec)
    4. mysql> show global variables like 'autocommit';
    5. +---------------+-------+
    6. | Variable_name | Value |
    7. +---------------+-------+
    8. | autocommit | OFF |
    9. +---------------+-------+
    10. 1 row in set (0.00 sec)
    11. 插入新行:
    12. mysql> insert into t values(2,1,1);
    13. Query OK, 1 row affected (0.00 sec)
    14. 仅当前会话可以查看到
    15. mysql> select * from t;
    16. +------+------+------+
    17. | id | var | foo |
    18. +------+------+------+
    19. | 1 | 1 | 1 |
    20. | 2 | 1 | 1 |
    21. +------+------+------+
    22. 2 rows in set (0.00 sec)
    23. SESSION 2
    24. 新会活未查询到相关的记录
    25. mysql> select * from t;
    26. +------+------+------+
    27. | id | var | foo |
    28. +------+------+------+
    29. | 1 | 1 | 1 |
    30. +------+------+------+
    31. 1 row in set (0.00 sec)
    32. SESSIOIN 1
    33. 会话1手动提交
    34. mysql> commit;
    35. Query OK, 0 rows affected (0.00 sec)
    36. SESSION 2
    37. 新会话再次查询,发现新的记录
    38. mysql> select * from t;
    39. +------+------+------+
    40. | id | var | foo |
    41. +------+------+------+
    42. | 1 | 1 | 1 |
    43. | 2 | 1 | 1 |
    44. +------+------+------+
    45. 2 rows in set (0.00 sec)
  3. (tx_isolation)查看当前数据库的事务隔离等级

    1. mysql> show global variables like 'tx_iso%';
    2. +---------------+-----------------+
    3. | Variable_name | Value |
    4. +---------------+-----------------+
    5. | tx_isolation | REPEATABLE-READ |
    6. +---------------+-----------------+
    7. 1 row in set (0.00 sec)

注意事项

伪代码如下:

  1. begin;
  2. insert into xxxxxx;
  3. create table xxxxxx;

写入的数据将会被持久化,无法进行回滚操作


事务的隔离等级

数据库事务的隔离级别有4个,由低到高依次为Read uncommitted、Read committed、Repeatable read、Serializable,这四个级别可以逐个解决脏读不可重复读幻读这几类问题。

Yes: 可能出现 No: 不会出现

隔离级别 脏读 不可重复读 幻读
Read uncommitted Yes Yes Yes
Read committed No Yes Yes
Repeatable read No No Yes
Serializable No No No

通常不可重复读针对update、delete操作,幻读针对insert操作,


实战讲解

查看当前全局隔离等级:

  1. mysql> show global variables like 'tx_isolation' \G
  2. *************************** 1. row ***************************
  3. Variable_name: tx_isolation
  4. Value: REPEATABLE-READ
  5. 1 row in set (0.01 sec)

READ-UNCOMMITTED事务隔离等级:

  1. mysql> set global tx_isolation='READ-UNCOMMITTED';
  2. Query OK, 0 rows affected (0.00 sec)
  3. mysql> show global variables like 'tx_isolation';
  4. +---------------+------------------+
  5. | Variable_name | Value |
  6. +---------------+------------------+
  7. | tx_isolation | READ-UNCOMMITTED |
  8. +---------------+------------------+
  9. 1 row in set (0.00 sec)
  10. SESSION 1
  11. mysql> begin;
  12. Query OK, 0 rows affected (0.00 sec)
  13. SESSION 2
  14. mysql> begin;
  15. Query OK, 0 rows affected (0.00 sec)
  16. SESSION 1
  17. mysql> select * from t;
  18. Empty set (0.00 sec)
  19. mysql> insert into t values(1,1);
  20. Query OK, 1 row affected (0.00 sec)
  21. mysql> select * from t;
  22. +------+------+------+
  23. | id | var | foo |
  24. +------+------+------+
  25. | 1 | 1 | 1 |
  26. +------+------+------+
  27. 1 row in set (0.00 sec)
  28. SESSION 2
  29. mysql> select * from t;
  30. +------+------+
  31. | id | a |
  32. +------+------+
  33. | 1 | 1 |
  34. +------+------+
  35. 1 row in set (0.00 sec)
  36. 会话2读到了会话1尚未提交的事务,脏读产生。

READ-COMMITTED隔离等级:

1.脏读

  1. SESSION 1
  2. mysql> set global tx_isolation='READ-COMMITTED';
  3. Query OK, 0 rows affected (0.00 sec)
  4. mysql> show global variables like 'tx_isolation';
  5. +---------------+----------------+
  6. | Variable_name | Value |
  7. +---------------+----------------+
  8. | tx_isolation | READ-COMMITTED |
  9. +---------------+----------------+
  10. 1 row in set (0.00 sec)
  11. mysql> begin;
  12. Query OK, 0 rows affected (0.00 sec)
  13. SESSION 2
  14. mysql> begin;
  15. Query OK, 0 rows affected (0.00 sec)
  16. SESSION 1
  17. mysql> select * from t;
  18. Empty set (0.00 sec)
  19. mysql> insert into t values(1,1);
  20. Query OK, 1 row affected (0.00 sec)
  21. mysql> select * from t;
  22. +------+------+
  23. | id | a |
  24. +------+------+
  25. | 1 | 1 |
  26. +------+------+
  27. 1 row in set (0.00 sec)
  28. SESSION 2
  29. mysql> select * from t;
  30. Empty set (0.01 sec)
  31. 会话2未读取到会话1中没有提交的事务,消除脏读现象。

2.不可重复读

  1. SESSION 1
  2. mysql> show global variables like 'tx_isolation';
  3. +---------------+----------------+
  4. | Variable_name | Value |
  5. +---------------+----------------+
  6. | tx_isolation | READ-COMMITTED |
  7. +---------------+----------------+
  8. 1 row in set (0.00 sec)
  9. mysql> begin;
  10. Query OK, 0 rows affected (0.00 sec)
  11. mysql> select * from t;
  12. +------+------+
  13. | id | a |
  14. +------+------+
  15. | 1 | 1 |
  16. +------+------+
  17. 1 row in set (0.00 sec)
  18. SESSION 2
  19. mysql> begin;
  20. Query OK, 0 rows affected (0.00 sec)
  21. mysql> select * from t;
  22. +------+------+
  23. | id | a |
  24. +------+------+
  25. | 1 | 1 |
  26. +------+------+
  27. 1 row in set (0.00 sec)
  28. SESSION 1
  29. mysql> update t set a = 3 where id = 1;
  30. Query OK, 1 row affected (0.00 sec)
  31. Rows matched: 1 Changed: 1 Warnings: 0
  32. SESSION 2
  33. mysql> select * from t;
  34. +------+------+
  35. | id | a |
  36. +------+------+
  37. | 1 | 1 |
  38. +------+------+
  39. 1 row in set (0.00 sec)
  40. SESSION 1
  41. mysql> commit;
  42. Query OK, 0 rows affected (0.00 sec)
  43. SESSION 2
  44. mysql> select * from t;
  45. +------+------+
  46. | id | a |
  47. +------+------+
  48. | 1 | 3 |
  49. +------+------+
  50. 1 row in set (0.00 sec)
  51. 会话1事务提交前后,会话2在同一个事务读取两次的数据不一致,不可重复读产生,针对updatedelete操作。delete操作不做演示。

3.幻读

  1. SESSION 1
  2. mysql> begin;
  3. Query OK, 0 rows affected (0.00 sec)
  4. mysql> select * from t;
  5. Empty set (0.00 sec)
  6. SESSION 2
  7. mysql> begin;
  8. Query OK, 0 rows affected (0.00 sec)
  9. mysql> select * from t;
  10. Empty set (0.00 sec)
  11. SESSION 1
  12. mysql> insert into t values(1,1);
  13. Query OK, 1 row affected (0.00 sec)
  14. SESSION 2
  15. mysql> select * from t;
  16. Empty set (0.00 sec)
  17. SESSION 1
  18. mysql> commit ;
  19. Query OK, 0 rows affected (0.00 sec)
  20. SESSION 2
  21. mysql> select * from t;
  22. +------+------+
  23. | id | a |
  24. +------+------+
  25. | 1 | 1 |
  26. +------+------+
  27. 1 row in set (0.00 sec)
  28. 会话1提交前后,会话2第二次查询到之前不存在的数据,幻读现象产生

REPEATABLE-READ隔离等级:

1.不可重复读

  1. SESSION 1
  2. mysql> show global variables like 'tx_isolation';
  3. +---------------+-----------------+
  4. | Variable_name | Value |
  5. +---------------+-----------------+
  6. | tx_isolation | REPEATABLE-READ |
  7. +---------------+-----------------+
  8. 1 row in set (0.00 sec)
  9. mysql> begin;
  10. Query OK, 0 rows affected (0.00 sec)
  11. mysql> select * from t;
  12. +------+------+
  13. | id | a |
  14. +------+------+
  15. | 1 | 1 |
  16. +------+------+
  17. 1 row in set (0.00 sec)
  18. SESSION 2
  19. mysql> begin;
  20. Query OK, 0 rows affected (0.00 sec)
  21. mysql> select * from t;
  22. +------+------+
  23. | id | a |
  24. +------+------+
  25. | 1 | 1 |
  26. +------+------+
  27. 1 row in set (0.00 sec)
  28. SESSION 1
  29. mysql> update t set a = 2 where id = 1;
  30. Query OK, 1 row affected (0.00 sec)
  31. Rows matched: 1 Changed: 1 Warnings: 0
  32. mysql> select * from t;
  33. +------+------+
  34. | id | a |
  35. +------+------+
  36. | 1 | 2 |
  37. +------+------+
  38. 1 row in set (0.00 sec)
  39. SESSION 2
  40. mysql> select * from t;
  41. +------+------+
  42. | id | a |
  43. +------+------+
  44. | 1 | 1 |
  45. +------+------+
  46. 1 row in set (0.00 sec)
  47. SESSION 1
  48. mysql> commit;
  49. Query OK, 0 rows affected (0.00 sec)
  50. mysql> select * from t;
  51. +------+------+
  52. | id | a |
  53. +------+------+
  54. | 1 | 2 |
  55. +------+------+
  56. 1 row in set (0.00 sec)
  57. SESSION 2
  58. mysql> select * from t;
  59. +------+------+
  60. | id | a |
  61. +------+------+
  62. | 1 | 1 |
  63. +------+------+
  64. 1 row in set (0.00 sec)
  65. mysql> commit;
  66. Query OK, 0 rows affected (0.00 sec)
  67. mysql> select * from t;
  68. +------+------+
  69. | id | a |
  70. +------+------+
  71. | 1 | 2 |
  72. +------+------+
  73. 1 row in set (0.00 sec)
  74. 会话1提交前后(会话2未提交),读取的数据一致,仅当会话2的事务提交之后才能看到其他事务提交的修改,消除不可重复读

2.幻读

  1. SESSION 1
  2. mysql> begin;
  3. Query OK, 0 rows affected (0.00 sec)
  4. mysql> select * from t;
  5. Empty set (0.00 sec)
  6. SESSION 2
  7. mysql> begin;
  8. Query OK, 0 rows affected (0.00 sec)
  9. mysql> select * from t;
  10. Empty set (0.00 sec)
  11. SESSION 1
  12. mysql> insert into t values(1,1);
  13. Query OK, 1 row affected (0.00 sec)
  14. mysql> select * from t;
  15. +------+------+
  16. | id | a |
  17. +------+------+
  18. | 1 | 1 |
  19. +------+------+
  20. 1 row in set (0.00 sec)
  21. SESSION 2
  22. mysql> select * from t;
  23. Empty set (0.00 sec)
  24. SESSION 1
  25. mysql> commit;
  26. Query OK, 0 rows affected (0.00 sec)
  27. mysql> select * from t;
  28. +------+------+
  29. | id | a |
  30. +------+------+
  31. | 1 | 1 |
  32. +------+------+
  33. 1 row in set (0.00 sec)
  34. SESSION 2
  35. mysql> select * from t;
  36. Empty set (0.00 sec)
  37. mysql> commit ;
  38. Query OK, 0 rows affected (0.00 sec)
  39. mysql> select * from t;
  40. +------+------+
  41. | id | a |
  42. +------+------+
  43. | 1 | 1 |
  44. +------+------+
  45. 1 row in set (0.00 sec)
  46. 会话1提交前后(会话2未提交),读取的数据一致,仅当会话2的事务提交之后才能看到其他事务写入的新数据,消除幻读

MySQL默认的隔离等级为REPEATABLE-READ,并未严格遵守相应的标准,请勿在线上环境随意修改此参数


MYSQL事务回滚的实现

ECCF9855-7DB8-497C-92B7-292AE684F674.png-62.2kB

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注