@nalan90
2017-12-19T18:03:41.000000Z
字数 8655
阅读 989
MySQL
事务的基本概念
事务(Transaction)是并发控制的基本单位。所谓的事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。例如,银行转账工作:从一个账号扣款并使另一个账号增款,这两个操作要么都执行,要么都不执行。所以,应该把它们看成一个事务。事务是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据一致性。
事务的基本特征
数据库的隔离现象
隔离现象 | 描述 |
---|---|
脏读(Dirty Read) | 事务B读到事务A尚未提交的数据变更 |
不可重复读(NonRepeatable Read) | 事务B后两次读取一条记录之间被事务A修改并提交,于是事务B读到了不一样的结果 |
幻读(Phantom Read) | 事务B按条件匹配到了若干行记录并修改。但是由于修改过程中事务A新插入了符合条件的记录,导致B更新完成后发现仍有符合条件却未被更新的记录 |
MYSQL的事务隔离级别
事务的持久化的实现
事务相关命令
相关参数说明
(autocommit)是否自动提交
mysql> show global variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
1 row in set (0.01 sec)
实例如下:
SESSION 1:
创建一张新表,并插入一条记录
mysql> create table t(id int ,var int ,foo int);
Query OK, 0 rows affected (0.02 sec)
mysql> desc t;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| var | int(11) | YES | | NULL | |
| foo | int(11) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
3 rows in set (0.01 sec)
mysql> select * from t;
Empty set (0.00 sec)
mysql> insert into t values(1,1,1);
Query OK, 1 row affected (0.00 sec)
mysql> select * from t;
+------+------+------+
| id | var | foo |
+------+------+------+
| 1 | 1 | 1 |
+------+------+------+
1 row in set (0.00 sec)
SESSION 2:
查看记录
mysql> select * from t;
+------+------+------+
| id | var | foo |
+------+------+------+
| 1 | 1 | 1 |
+------+------+------+
1 row in set (0.00 sec)
关闭自动提交,执行如上操作,观察两个session的数据
SESSION 1
mysql> set global autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> show global variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | OFF |
+---------------+-------+
1 row in set (0.00 sec)
插入新行:
mysql> insert into t values(2,1,1);
Query OK, 1 row affected (0.00 sec)
仅当前会话可以查看到
mysql> select * from t;
+------+------+------+
| id | var | foo |
+------+------+------+
| 1 | 1 | 1 |
| 2 | 1 | 1 |
+------+------+------+
2 rows in set (0.00 sec)
SESSION 2
新会活未查询到相关的记录
mysql> select * from t;
+------+------+------+
| id | var | foo |
+------+------+------+
| 1 | 1 | 1 |
+------+------+------+
1 row in set (0.00 sec)
SESSIOIN 1
会话1手动提交
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
SESSION 2
新会话再次查询,发现新的记录
mysql> select * from t;
+------+------+------+
| id | var | foo |
+------+------+------+
| 1 | 1 | 1 |
| 2 | 1 | 1 |
+------+------+------+
2 rows in set (0.00 sec)
(tx_isolation)查看当前数据库的事务隔离等级
mysql> show global variables like 'tx_iso%';
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ |
+---------------+-----------------+
1 row in set (0.00 sec)
注意事项
伪代码如下:
begin;
insert into xxxxxx;
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操作,
实战讲解
查看当前全局隔离等级:
mysql> show global variables like 'tx_isolation' \G
*************************** 1. row ***************************
Variable_name: tx_isolation
Value: REPEATABLE-READ
1 row in set (0.01 sec)
READ-UNCOMMITTED事务隔离等级:
mysql> set global tx_isolation='READ-UNCOMMITTED';
Query OK, 0 rows affected (0.00 sec)
mysql> show global variables like 'tx_isolation';
+---------------+------------------+
| Variable_name | Value |
+---------------+------------------+
| tx_isolation | READ-UNCOMMITTED |
+---------------+------------------+
1 row in set (0.00 sec)
SESSION 1
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
SESSION 2
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
SESSION 1
mysql> select * from t;
Empty set (0.00 sec)
mysql> insert into t values(1,1);
Query OK, 1 row affected (0.00 sec)
mysql> select * from t;
+------+------+------+
| id | var | foo |
+------+------+------+
| 1 | 1 | 1 |
+------+------+------+
1 row in set (0.00 sec)
SESSION 2
mysql> select * from t;
+------+------+
| id | a |
+------+------+
| 1 | 1 |
+------+------+
1 row in set (0.00 sec)
会话2读到了会话1尚未提交的事务,脏读产生。
READ-COMMITTED隔离等级:
1.脏读
SESSION 1
mysql> set global tx_isolation='READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)
mysql> show global variables like 'tx_isolation';
+---------------+----------------+
| Variable_name | Value |
+---------------+----------------+
| tx_isolation | READ-COMMITTED |
+---------------+----------------+
1 row in set (0.00 sec)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
SESSION 2
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
SESSION 1
mysql> select * from t;
Empty set (0.00 sec)
mysql> insert into t values(1,1);
Query OK, 1 row affected (0.00 sec)
mysql> select * from t;
+------+------+
| id | a |
+------+------+
| 1 | 1 |
+------+------+
1 row in set (0.00 sec)
SESSION 2
mysql> select * from t;
Empty set (0.01 sec)
会话2未读取到会话1中没有提交的事务,消除脏读现象。
2.不可重复读
SESSION 1
mysql> show global variables like 'tx_isolation';
+---------------+----------------+
| Variable_name | Value |
+---------------+----------------+
| tx_isolation | READ-COMMITTED |
+---------------+----------------+
1 row in set (0.00 sec)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t;
+------+------+
| id | a |
+------+------+
| 1 | 1 |
+------+------+
1 row in set (0.00 sec)
SESSION 2
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t;
+------+------+
| id | a |
+------+------+
| 1 | 1 |
+------+------+
1 row in set (0.00 sec)
SESSION 1
mysql> update t set a = 3 where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
SESSION 2
mysql> select * from t;
+------+------+
| id | a |
+------+------+
| 1 | 1 |
+------+------+
1 row in set (0.00 sec)
SESSION 1
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
SESSION 2
mysql> select * from t;
+------+------+
| id | a |
+------+------+
| 1 | 3 |
+------+------+
1 row in set (0.00 sec)
会话1事务提交前后,会话2在同一个事务读取两次的数据不一致,不可重复读产生,针对update、delete操作。delete操作不做演示。
3.幻读
SESSION 1
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t;
Empty set (0.00 sec)
SESSION 2
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t;
Empty set (0.00 sec)
SESSION 1
mysql> insert into t values(1,1);
Query OK, 1 row affected (0.00 sec)
SESSION 2
mysql> select * from t;
Empty set (0.00 sec)
SESSION 1
mysql> commit ;
Query OK, 0 rows affected (0.00 sec)
SESSION 2
mysql> select * from t;
+------+------+
| id | a |
+------+------+
| 1 | 1 |
+------+------+
1 row in set (0.00 sec)
会话1提交前后,会话2第二次查询到之前不存在的数据,幻读现象产生
REPEATABLE-READ隔离等级:
1.不可重复读
SESSION 1
mysql> show global variables like 'tx_isolation';
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ |
+---------------+-----------------+
1 row in set (0.00 sec)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t;
+------+------+
| id | a |
+------+------+
| 1 | 1 |
+------+------+
1 row in set (0.00 sec)
SESSION 2
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t;
+------+------+
| id | a |
+------+------+
| 1 | 1 |
+------+------+
1 row in set (0.00 sec)
SESSION 1
mysql> update t set a = 2 where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from t;
+------+------+
| id | a |
+------+------+
| 1 | 2 |
+------+------+
1 row in set (0.00 sec)
SESSION 2
mysql> select * from t;
+------+------+
| id | a |
+------+------+
| 1 | 1 |
+------+------+
1 row in set (0.00 sec)
SESSION 1
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t;
+------+------+
| id | a |
+------+------+
| 1 | 2 |
+------+------+
1 row in set (0.00 sec)
SESSION 2
mysql> select * from t;
+------+------+
| id | a |
+------+------+
| 1 | 1 |
+------+------+
1 row in set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t;
+------+------+
| id | a |
+------+------+
| 1 | 2 |
+------+------+
1 row in set (0.00 sec)
会话1提交前后(会话2未提交),读取的数据一致,仅当会话2的事务提交之后才能看到其他事务提交的修改,消除不可重复读
2.幻读
SESSION 1
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t;
Empty set (0.00 sec)
SESSION 2
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t;
Empty set (0.00 sec)
SESSION 1
mysql> insert into t values(1,1);
Query OK, 1 row affected (0.00 sec)
mysql> select * from t;
+------+------+
| id | a |
+------+------+
| 1 | 1 |
+------+------+
1 row in set (0.00 sec)
SESSION 2
mysql> select * from t;
Empty set (0.00 sec)
SESSION 1
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t;
+------+------+
| id | a |
+------+------+
| 1 | 1 |
+------+------+
1 row in set (0.00 sec)
SESSION 2
mysql> select * from t;
Empty set (0.00 sec)
mysql> commit ;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t;
+------+------+
| id | a |
+------+------+
| 1 | 1 |
+------+------+
1 row in set (0.00 sec)
会话1提交前后(会话2未提交),读取的数据一致,仅当会话2的事务提交之后才能看到其他事务写入的新数据,消除幻读
MySQL默认的隔离等级为REPEATABLE-READ,并未严格遵守相应的标准,请勿在线上环境随意修改此参数
MYSQL事务回滚的实现