隔离性说明
当多个线程同时访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致各种并发问题
- 脏读: 对于两个事务 T1, T2。T1 读取了已经被 T2 更新但还没有被提交的字段。 之后, 若 T2 回滚, T1读取的内容就是临时且无效的。
- 不可重复读: 对于两个事务T1, T2, T1 读取了一个字段, 然后 T2 更新了该字段。 之后, T1再次读取同一个字段, 值就不同了。
- 幻读: 对于两个事务T1, T2, T1 从一个表中读取了一个字段, 然后 T2 在该表中插入了一些新的行。 之后, 如果 T1 再次读取同一个表, 就会多出几行。
对于数据库来说,必须具有隔离并发运行各个事务的能力, 使它们不会相互影响, 避免各种并发问题
一个事务与其他事务隔离的程度称为隔离级别。数据库规定了多种事务隔离级别, 不同隔离级别对应不同的干扰程度, 隔离级别越高, 数据一致性就越好, 但并发性越弱
隔离级别说明
- MySQL共提供了4中隔离级别 | 隔离级别 | 描述 | | :—-: | :—-: | | READ UNCOMMITTED(读未提交数据) | 允许事务读取未被其他事务提交的变更,这种隔离级别脏读、不可重复读和幻读的问题都可能会出现 | | READ COMMITTED(读已提交数据) | 允许事务读取已经被其他事务提交的变更,这种隔离级别可以避免脏读,但是不可重复和幻读问题依然会出现 | | REPEATABLE READ(可重复读) | 确保在一个事务中,读取相同字段的值不会被改变,同时禁止其他事务对这个字段进行更新(行锁),可以避免脏读不可重复读,在MySQL5.5版本以上可以避免幻读 | | SERIALIZABLE(串行化) | 相当于表锁,一个事务在操作该表的时候,禁止其他事务对该表进行更新、插入和删除操作,上述的所有问题都可以避免,但是效率低下 |
设置隔离级别
查看当前的隔离级别
SELECT @@tx_isolation;
查看全局的隔离级别
SELECT @@global.tx_isolation;
设置当前连接的隔离级别 ```sql
设置隔离级别为读未提交
set tx_isolation =’read-uncommitted’;
设置隔离级别为读已提交
set tx_isolation =’read-committed’;
设置隔离级别为可重复读
set tx_isolation =’repeatable-read’;
设置隔离级别为串行化
set tx_isolation =’serializable’;
3. 设置全局连接的隔离级别
```sql
# 设置全局隔离级别为读未提交
set global tx_isolation ='read-uncommitted';
# 设置全局隔离级别为读已提交
set global tx_isolation ='read-committed';
# 设置全局隔离级别为可重复读
set global tx_isolation ='repeatable-read';
# 设置全局隔离级别为串行化
set global tx_isolation ='serializable';
测试隔离级别
读未提交测试
- 开启两个窗口连接MySQL,每个窗口都代表一个事务
两个事务都设置当前的隔离级别为读未提交
set tx_isolation ='read-uncommitted';
开启事务
start transaction;
第一个窗口插入一条数据,但是还未提交,然后使用第二个窗口查询,就可以看到第一个窗口未提交的数据
- 第一个窗口rollback,然后再用第二个窗口查询数据,就看不到刚才插入的数据了,这个就是脏读
读已提交测试
- 设置两个窗口的当前隔离级别为读已提交,然后两个窗口开启事务 ```sql set tx_isolation =’read-committed’;
start transaction;
2. 还是一样在窗口1修改一条数据,但是未提交事务,使用窗口2查询就不能查到刚才窗口1修改的数据,这就解决了脏读的问题
![image.png](https://cdn.nlark.com/yuque/0/2020/png/2463114/1600298583755-3c4949d4-ba4c-40c7-ad3f-f931e58d12a8.png#align=left&display=inline&height=804&margin=%5Bobject%20Object%5D&name=image.png&originHeight=804&originWidth=1493&size=69296&status=done&style=none&width=1493)
3. 窗口1提交事务后,窗口2才可以查询到,但是在窗口2这一个事务中,出现查同一张表的一条记录出现不同的结果,这个就是不可重复读的问题了
![image.png](https://cdn.nlark.com/yuque/0/2020/png/2463114/1600298608181-9fb00e5b-848b-4a7d-b936-25277cc8898e.png#align=left&display=inline&height=806&margin=%5Bobject%20Object%5D&name=image.png&originHeight=806&originWidth=1488&size=83403&status=done&style=none&width=1488)
<a name="IBGZO"></a>
### 不可重复读测试
1. 设置两个窗口隔离级别为可重复读,并开启事务
```sql
set tx_isolation ='repeatable-read';
start transaction;
- 在窗口1修改一条记录,但是没提交,窗口2肯定读不到
- 然后窗口1提交事务,窗口2还是读不到,这就避免了不可重复读的问题
- 窗口2提交事务,在查询,就可以查到刚才窗口1修改后的数据了
- 如果窗口1和窗口2修改同一条记录,窗口1先修改没有提交事务,窗口2修改的时候就会被阻塞住(行锁),直到窗口1提交事务,如果窗口2也提交了事务,那么就会将窗口1修改的数据覆盖