事务是逻辑上的一组操作,这组操作要么全部成功,要么全部失败
* 原子性(Atomicity)
事务是最小的工作单元,不可再分
* 一致性(Consistency)
事务要求的DML语句操作的时候,必须保证同时成功或者同时失败 # DML Manipulation 数据操纵语言 用于改变数据库数据 1) 插入:INSERT 2) 更新:UPDATE 3) 删除:DELETE
* 隔离性(Isolation)
事务A和事务B之间具有隔离
* 持久性(Durability)
是事务的保证,事务终结的标志。【内存中的数据持久到硬盘文件中】
- 开启事务:start transaction
- 提交事务:commit transaction
- 回滚事务:rolback transaction
- 事务结束:end transaction
commit; 提交
rollback; 回滚
savepoint; # TCL 用于维护数据的一致性
任何一条DML语句执行,标志事务的开启
提交或者回滚
在MySQL数据库管理系统中,默认情况下,事务是自动提交的,也就是说,只要执行一条DML语句,开启了事务,并且提交了事务。
mysql> show variables like '%auto%';
+-----------------------------+-------+
| Variable_name | Value |
+-----------------------------+-------+
| auto_increment_increment | 1 |
| auto_increment_offset | 1 |
| autocommit | ON |
| automatic_sp_privileges | ON |
| innodb_autoextend_increment | 64 |
| innodb_autoinc_lock_mode | 1 |
| innodb_stats_auto_recalc | ON |
| sql_auto_is_null | OFF |
+-----------------------------+-------+
8 rows in set, 1 warning (0.01 sec)
start transaction; 手动开启事务
DML语句…
DML语句…
DML语句…
commit; 手动提交事务【事务成功的结束】
start transaction; 手动开启事务
DML语句…
DML语句…
DML语句…
rollback; 手动回滚事务【事务失败的结束】
# 以下关闭和打开自动提交机制,只对当前会话有效。
set autocommit = off;
或者
set session autocommit = off;
set autocommit = on;
或者
set session autocommit = on;
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
read uncommitted | √ | √ | √ |
read committed | × | √ | √ |
repeatable read | × | × | √ |
serializable | × | × | × |
# 查看当前会话的隔离级别:
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)
# 查看全局的事务隔离级别:
mysql> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ | # MySQL数据库管理系统默认的隔离级别:
+-----------------------+
1 row in set, 1 warning (0.00 sec)
- 事务A和事务B,事务A未提交的数据,事务B可以读取到。
- 这里读取到的数据可以叫做“脏数据”或者叫做“Dirty Read”
- 这种隔离级别是最低级别,这种级别一般都是理论上存在的,数据库默认的隔离级别一般都是高于该隔离级别的。
- 事务A和事务B,事务A提交的数据,事务B才能读取到。
- 这种隔离级别高于上面的读未提交
- 换句话说:对方事务提交之后的数据,我当前事务才能够读取到
- 这种隔离级别可以避免脏数据
- 这种隔离级别会导致:“不可重复读取”
- Oracle数据库管理系统默认的隔离级别:读已提交
- 事务A和事务B,事务A提交之后的数据,事务B读取不到。
- 事务B是可重复读取数据的。
- 这种隔离级别高于读已提交。
- 换句话说:对方提交之后的数据我还是读取不到。
- 这种隔离级别可以避免“不可重复读”,达到可重复读取。
- MySQL数据库管理系统默认的隔离级别:可重复读
- 虽然可以达到“可重复读”的结果,但是会导致:“幻象读”
- 事务A和事务B,事务A在操作数据库表中数据的时候,事务B只能排队等待。
- 这种隔离级别一般很少使用,吞吐量太低。用户体验不好。
- 这种隔离级别可以避免“幻象读”,每一次读取的都是数据库表中真实的记录。
- 事务A和事务B 不再并发,是串行执行的。
可选值:
- READ-UNCOMMITTED
- READ-COMMITTED
- REPEATABLE-READ
- SERIALIZABLE
-------------------my.ini---------------------
[mysqld]
transaction-isolation = READ-COMMITTED
-------------------my.ini---------------------
命令格式:
set [无/session/global] transaction isolation level <isolation-level>;
<isolation-level>可选值:
- READ-UNCOMMITTED
- READ-COMMITTED
- REPEATABLE-READ
- SERIALIZABLE
设置事务的隔离级别作用于全局:
set global transaction isolation level <level>;
设置事务的隔离级别作用于当前会话:
set transaction isolation level <level>;
或者
set session transaction isolation level <level>;
mysql> set global transaction isolation level read uncommitted;
①会话1
mysql> use test;
Database changed
mysql> select * from tx1;
Empty set (0.00 sec)
mysql> start transaction; # 手动开启事务A,等于关闭当前的自动提交
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO `test`.`tx1`(`id`, `c1`, `c2`) VALUES (1, 'a', 'a');
Query OK, 1 row affected (0.00 sec)
②会话2
mysql> select * from tx1;
+----+------+------+
| id | c1 | c2 |
+----+------+------+
| 1 | a | a |
+----+------+------+
1 row in set (0.00 sec)
③会话1
mysql> update tx1 set c1='aa',c2='bb';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
④会话2
mysql> select * from tx1;
+----+------+------+
| id | c1 | c2 |
+----+------+------+
| 1 | aa | bb | # 脏读 意味着事务A仍未提交,但它任何一条数据变化,其它事务都可以看到
+----+------+------+
1 row in set (0.00 sec)
这种隔离级别出现的问题是——不可重复读(Nonrepeatable Read):不可重复读意味着我们在同一个事务中执行完全相同的select语句时可能看到不一样的结果。 导致原因可能有:(1)有一个交叉的事务有新的commit,导致了数据的改变;(2)一个数据库被多个实例操作时,同一事务的其他实例在该实例处理其间可能会有新的commit
mysql> set global transaction isolation level read committed;
mysql> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| READ-COMMITTED |
+-----------------------+
1 row in set, 1 warning (0.00 sec)
①会话1
mysql> use test;
Database changed
mysql> select * from tx1;
Empty set (0.00 sec)
mysql> start transaction; # 手动开启事务,等于关闭当前的自动提交
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO `test`.`tx1`(`id`, `c1`, `c2`) VALUES (1, 'a', 'a');
Query OK, 1 row affected (0.00 sec)
②会话2
mysql> use test;
Database changed
mysql> select * from tx1;
Empty set (0.01 sec)
③会话1
# 继续在会话1窗口
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
④会话2
mysql> select * from tx1;
+----+------+------+
| id | c1 | c2 |
+----+------+------+
| 1 | a | a |
+----+------+------+
1 row in set (0.00 sec)
此级别可能出现的问题——幻读(Phantom Read):当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行
mysql> set global transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)
mysql> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ |
+-----------------------+
1 row in set, 1 warning (0.00 sec)
①会话1
mysql> use test;
Database changed
mysql> select * from tx1;
Empty set (0.00 sec)
mysql> start transaction; # 手动开启事务,等于关闭当前的自动提交
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO `test`.`tx1`(`id`, `c1`, `c2`) VALUES (1, ' REPEATABLE-READ', ' REPEATABLE-READ');
Query OK, 1 row affected (0.00 sec)
②会话2
mysql> use test;
Database changed
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
③会话1
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
④会话2
mysql> select * from tx1; # 会话1 已经提交了,仍然无法读到内容。 说明级别3 解决了 不可重复读 的问题
Empty set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from tx1; # 只有当会话2提交了,它才能够看到数据变化
+----+------------------+------------------+
| id | c1 | c2 |
+----+------------------+------------------+
| 1 | REPEATABLE-READ | REPEATABLE-READ |
+----+------------------+------------------+
1 row in set (0.00 sec)
7.3.4 第四级别:可串行化 Serializable
(1)这是最高的隔离级别 (2)它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。 (3)在这个级别,可能导致大量的超时现象和锁竞争
mysql> set global transaction isolation level serializable;
Query OK, 0 rows affected (0.00 sec)
mysql> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| SERIALIZABLE |
+-----------------------+
1 row in set, 1 warning (0.00 sec)