1、事务的四个特性
事务是一个或多个SQL语句组成的一个不可分割的单元。事务中的一组SQL语句,要么全部成功,要么全部失败。四个特性 ACID
原子性 atomic
一致性 consistency
隔离性 isolation 针对数据库中的并发来说,隔离性越好,并发性越低。根据的是innodb的锁机制
持久性 durability redo日志,保证数据的持久性,极端情况 commit后,服务器宕机,数据还没有持久化到磁盘,就需要依靠redo日志了。
ACD依靠的是redo、undo日志。I 依靠的是锁机制。
2、并发存在的问题
以 user 表为例,进行描述。
select * from user;
+----+----------+-----+-----+
| id | name | age | sex |
+----+----------+-----+-----+
| 1 | zhangsan | 22 | M |
| 2 | lisi | 22 | W |
+----+----------+-----+-----+
2 rows in set (0.00 sec)
1、脏读
//设置隔离级别为读未提交 read-uncommitted
mysql> set tx_isolation='READ-UNCOMMITTED';
Query OK, 0 rows affected, 1 warning (0.00 sec)
事务A
A1、mysql> begin;
Query OK
A2、mysql> update user set age=30 where name='zhangsan';
Query OK
A3、mysql> rollback;
Query OK
事务B
B1、mysql> begin;
Query OK
B2、mysql> select * from user where name='zhangsan';
+----+----------+-----+-----+
| id | name | age | sex |
+----+----------+-----+-----+
| 1 | zhangsan | 22 | M |
+----+----------+-----+-----+
B3、mysql> select * from user where name='zhangsan';
+----+----------+-----+-----+
| id | name | age | sex |
+----+----------+-----+-----+
| 1 | zhangsan | 30 | M |
+----+----------+-----+-----+
当事务A,事务B均开启事务,
首先事务B查询,执行了B2,得到了结果如上。
事务A开始进行update,执行A2,
事务B再次进行查询,执行B3,得到结果,此时的结果要用到相应的业务。
事务A进行回滚,未进行commit。而事务B对A未提交的业务已经进行使用。
2、不可重复读
//设置隔离级别为读已提交 read-commited;
set tx_isolation='READ-COMMITTED';
Query OK, 0 rows affected, 1 warning (0.00 sec)
事务A
A1、mysql> begin;
Query OK, 0 rows affected (0.00 sec)
A2、mysql> update user set age=30 where name='zhangsan';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
A3、mysql> commit;
Query OK, 0 rows affected (0.00 sec)
事务B
begin;
Query OK, 0 rows affected (0.00 sec)
B1 、mysql> select * from user where name='zhangsan';
+----+----------+-----+-----+
| id | name | age | sex |
+----+----------+-----+-----+
| 1 | zhangsan | 22 | M |
+----+----------+-----+-----+
1 row in set (0.00 sec)
B2、mysql> select * from user where name='zhangsan';
+----+----------+-----+-----+
| id | name | age | sex |
+----+----------+-----+-----+
| 1 | zhangsan | 22 | M |
+----+----------+-----+-----+
1 row in set (0.00 sec)
B3、mysql> select * from user where name='zhangsan';
+----+----------+-----+-----+
| id | name | age | sex |
+----+----------+-----+-----+
| 1 | zhangsan | 30 | M |
+----+----------+-----+-----+
1 row in set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
和上面一样,在事务A,执行A2,进行updata后
事务B再次进行查询,执行B2,查询结果和未修改前一样。
当事务A commit后,事务B再次查询,执行B3,得到更新后的结果。
3、幻读
在很多博客中,会这样说,幻读是事务A对表进行增加或者删除,然后在事务B中,select的时候,会直接发现改变,经过我的多次实验,感觉这么说多少有点不太准确。可以看下面的描述。
设置隔离级别为 可重复读。这也是innoDB默认的隔离级别。
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)
首先,可重复读可以解决 脏读和不可重复读的问题,
对于解决不可重复读的问题。
事务B在未commit事务前,不管事务A是如何 update,
事务B都会和事务A begin 之前的结果一样。
看一下幻读:
事务A:
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
A1 mysql> insert into user(name, age, sex) values('aaa', 19, 'M');
Query OK, 1 row affected (0.00 sec)
A2 mysql> select * from user where age=19;
+----+------+-----+-----+
| id | name | age | sex |
+----+------+-----+-----+
| 15 | aaa | 19 | M |
+----+------+-----+-----+
1 row in set (0.00 sec)
A3 mysql> commit;
Query OK, 0 rows affected (0.00 sec)
事务B:
B1 mysql> begin;
Query OK, 0 rows affected (0.00 sec)
事务A insert 前,未commit
B2 mysql> select * from user where age=19;
Empty set (0.00 sec)
事务A insert 后,未commit
B3 mysql> select * from user where age=19;
Empty set (0.01 sec)
事务A commit后,查询结果还是空。
B4 mysql> select * from user where age=19;
Empty set (0.00 sec)
但此时已经有幻读了,但是还是看不到,需要update。
B5 mysql> update user set name='aaa' where age=19;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0
这个就是幻读,上下结果不一样,
B6 mysql> select * from user where age=19;
+----+------+-----+-----+
| id | name | age | sex |
+----+------+-----+-----+
| 15 | aaa | 19 | M |
+----+------+-----+-----+
1 row in set (0.00 sec)
B7 mysql> commit;
Query OK, 0 rows affected (0.00 sec)
3、隔离级别
MySQL支持的四种隔离级别是:
- 1、TRANSACTION_READ_UNCOMMITTED。
读未提交。说明在提交前一个事务可以看到另一个事务 的变化。这样读脏数据,不可重复读和虚读都是被允许的。
- 2、TRANSACTION_READ_COMMITTED。
读已提交。说明读取未提交的数据是不允许的。这个级别仍 然允许不可重复读和虚读产生。
- 3、TRANSACTION_REPEATABLE_READ。
可重复读。说明事务保证能够再次读取相同的数据而不会失 败,但虚读仍然会出现。
- 4、TRANSACTION_SERIALIZABLE。
串行化。是最高的事务级别,它防止读脏数据,不可重复读和虚 读。
串行化是隔离级别最高的,开启 事务A 和 事务B 后,便不能再插入删除了。
可重复读 中的幻读现象,insert或者delete,没有update的话,也不会产生幻读现象。
4、 常用语句
查询隔离级别:
select @@tx_isolation;
设置隔离级别:
set tx_isolation='隔离级别';
隔离级别四种可选择的:
read-uncommitted read-committed repeatable-read serializable
set tx_isolation='read-uncommitted';