重新学习事务的隔离级别和数据库问题

经过一轮面试,发现自己的很多知识是混沌状态,处于一种感性的状态,没有深究。也可能是当时没有看懂,就掠过了。现在重读,温故知新。

1、脏读。

就是读到了脏数据。(dirty,脏的,不对的。)

step

Session A

Session A

0

SET @@tx_isolation='read-uncommited';

SET @@tx_isolation='read-uncommited';

1

Begin;

Begin;

2

Select * from t;

+--------+

| N_CODE |

+--------+

|      1 |

+--------+

1 row in set

 

3

 

INSERT into `t` SELECT 2; //没有提交

4

Select * from t;

+--------+

| N_CODE |

+--------+

|      1 |

|      2 |

+--------+

2 rows in set

 

脏读是是发生在'read-uncommited'的隔离级别中的,即B事务还没有提交,A事务就能够读到。读到的是脏数据。

现在为了解决这问题,就把数据库隔离级别设置为提交读。'read-commited',即提交之后才能读到。


2、不可重复读。

step

Session A

Session A

0

SET @@tx_isolation='read-commited';

SET @@tx_isolation='read-commited';

1

Begin;

Begin;

2

Select * from t;

+--------+

| N_CODE |

+--------+

|      1 |

+--------+

1 row in set

 

3

 

INSERT into `t` SELECT 2; //没有提交

4

Select * from t;

+--------+

| N_CODE |

+--------+

|      1 |

+--------+

1 row in set

 

5

 

Commit; //提交

6

Select * from t;

+--------+

| N_CODE |

+--------+

|      1 |

|      2 |

+--------+

2 rows in set

 

 

在第3、4步的时候B没有提交,A只读到了1,没有读到B提交的2数据。解决了脏(未提交)读的问题。

在5、6步的时候B提交了,A也读到了B提交的数据。是正常的,可以接受的。

但是这个违反了数据库事务一致性的要求,即两次(第四步和第六步)读到的数据不一致。

 

所以,如果能够接受这个问题存在的,无关大雅的,就把数据库的隔离级别设置为了提交读。如果不能忍受这个问题的,就得继续想办法解决,于是把数据库隔离级别设置为Repeatable Read,可重复读。


3、幻读。

step

Session A

Session A

0

SET @@tx_isolation='Repeatable Read ';

SET @@tx_isolation='Repeatable Read ';

1

Begin;

Begin;

2

Select * from t;

+--------+

| N_CODE |

+--------+

|      1 |

+--------+

1 row in set

 

3

 

INSERT into `t` SELECT 2; //没有提交

4

Select * from t;

+--------+

| N_CODE |

+--------+

|      1 |

+--------+

1 row in set

 

5

 

Commit; //提交

6

Select * from t;

+--------+

| N_CODE |

+--------+

|      1 |

+--------+

1 row in set

 

这样就没有问题了,符合了一致性。

但是这时候又会出现一个问题,如果A在第六步之后执行了第七步INSERT into `t` SELECT 2;(因为A认为没有2这条数据,所以当然可以添加了)。结果怎样?继续:

6

Select * from t;

+--------+

| N_CODE |

+--------+

|      1 |

+--------+

1 row in set

                                                               

7

mysql> INSERT into `t` SELECT 2;

1062 - Duplicate entry '2' for key 1

//主键冲突??表里不是没有2这条数据吗,难道是幻觉?

 

 

上面的问题就是幻读。在第六步读到的是幻觉,只有1数据,但实际真实的数据库中是有两条数据(1和2)了。

这个问题??

可以认为不是问题,符合规律,可以接受。或者select 。。。lock in share mode。或者在提升数据库的隔离级别,Serializable Read,序列化读。不过这样的话读都要上锁了... 在并发环境中性能会下降。

 

综合:

数据库的隔离级别

 

隔离级别

是否存在脏读

是否存在不可重复读

是否存在幻读

未提交读

Read uncommitted

Y

Y

Y

提交读(常用)

Read committed

N

Y

Y

可重复读

Repeatable Read

N

N

Y

序列化读

Serializable Read

N

N

N

 

 

具体选择哪个,要看公司的业务需要了。自己选择吧。



4、丢失更新(补充)。

这一类数据库问题是程序员最容易犯的一类错误,并且极不容易被发现。不依靠数据库的隔离级别进行解决,需要使用for update排他锁解决。


时间

转账事务A

取款事务B

T1

 

开始事务

T2

开始事务

                         

T3

               

查询账户余额为1000元   (for update)

T4

查询账户余额为1000元

(for update)

                         

T5

 

取出100元把余额改为900元

T6

 

提交事务           

T7

汇入100元

 

T8

提交事务

 

T9

把余额改为1100 元(丢失更新)

 





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值