在介绍数据库隔离级别之前,先了解一下数据库的事务,通俗来讲,据库的事务是一个逻辑划分,可以理解为一组数据库的操作(一个或多个数据库操作),事务具有4个特性(ACID),即Atomicity(原子性),Consistency(一致性),Isolation(隔离性)和 Durability(持久性):
原子性(Atomicity):原子性是指一个事务中的所有操作,要么全部成功,要么全部失败,如果失败,就回滚到事务开始前的状态。
一致性(Consistency):一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。拿转账举栗子,A账户和B账户之间相互转账,无论如何操作,A、B账户的总金额都必须是不变的。
隔离性(Isolation):隔离性是当多个用户 并发 访问数据库时,如果操作同一张表,数据库则为每一个用户都开启一个事务,且事务之间互不干扰,也就是说事务之间的并发是隔离的。再举个栗子,现有两个并发的事务T1和T2,T1要么在T2开始前执行,要么在T2结束后执行,如果T1先执行,那T2就在T1结束后在执行。关于数据的隔离,将在后文讲到。
持久性(Durability):持久性就是指如果事务一旦被提交,数据库中数据的改变就是永久性的,即使断电或者宕机的情况下,也不会丢失提交的事务操作。
什么是事务的隔离性(Isolation)呢?
隔离性是指,多个用户的并发事务访问同一个数据库时,一个用户的事务不应该被其他用户的事务干扰,多个并发事务之间要相互隔离。
如果不考虑隔离性,会发生什么事呢?
1.脏读(Dirty Read):
脏读是指一个事务在处理数据的过程中,读取到另一个未提交事务的数据。
脏读最大的问题就是可能读到不存在的数据。比如下图中,事务B的更新数据被事务A读取,但是事务B回滚了,数据全部还原,也就是说事务A刚刚读到的数据并没有存在于数据库中。
2.不可重复读(nonrepeatable read):
不可重复读是指对于数据库中的某个数据,一个事务范围内的多次查询却返回了不同的结果,这是由于在查询过程中,数据被另外一个事务修改并提交了。具体如下图,Trans B在Trans A两次读取数据之间对数据进行修改,导致Trans A两次读取结果不一致。
不可重复读和脏读的区别是,脏读读取到的是一个未提交的数据,而不可重复读读取到的是另一个事务提交的数据。
而不可重复读在一些情况也并不影响数据的正确性,比如需要多次查询的数据也是要以最后一次查询到的数据为主。
3.幻读(Phantom read)
幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。
幻读和不可重复读都是读取了另一事务已经提交的数据(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。
不可重复读和幻读是初学者不易分清的概念,总的来说,解决不可重复读的方法是 锁行,解决幻读的方式是 锁表。
四种隔离级别解决了上述问题
1.未提交读(Read uncommitted):
这种事务隔离级别下,select语句不加锁,事务中修改的数据,即使没有提交,对其他事务也都是可见的。
此时,可能读取到不一致的数据,即“读脏 ”。这是并发最高,一致性最差的隔离级别。
2.提交读(Read committed):
一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。
大多数数据库系统的默认隔离级别都是提交读(但Mysql不是)。提交读满足前面提到的隔离性的简单定义:一个事务开始时,只能“看见”已经提交的事务所做的修改。可避免脏读,无法避免不可重复读发生。
因为两次执行同样的查询,可能会得到不一样的结果,这个级别有时候也叫做不可重复读(nonrepeatable read)。
3.可重复读(Repeatable read):
该级别保证了在同一事务内多次读取同一数据时,结果是一致的。为了实现这一点,当事务执行查询时,它会锁定查询的列或行,确保其他事务在此期间不能修改这些数据。解决 脏读 、不可重复读 的问题,是MySql默认隔离级别。
但这种锁定策略不能解决幻象读。例如,当事务执行范围查询如“select name from Student where id>10”并锁定相关行时,另一个事务仍然可以添加新的学生记录。这可能导致在第二次执行相同查询时,出现新的学生记录,即“幻读”。
4.串行化(Serializable ):
可串行化是最高的隔离级别。它通过强制事务串行执行,避免了脏读、不可重复读、幻读的问题。
简单来说,可串行化会在读取的每一行数据上都加上锁,所以可能导致大量的超时和锁争用问题。实际应用中也很少用到这个隔离级别,只有在非常需要确保数据的一致性而且可以接受没有并发的情况下,才考虑用该级别。
以上四种隔离级别最高的是 Serializable 级别,最低的是 Read uncommitted 级别,当然级别越高,执行效率就越低。像 Serializable 这样的级别,就是以 锁表 的方式,使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。Oracle和SQL Server默认的隔离级别为Read committed,MySQL默认的隔离级别为Repeatable read。
SQL Server和MySQL数据库支持上面四种隔离级别,而 Oracle数据库只支持Serializable (串行化) 级别和 Read committed (读已提交) 这两种级别。
本文转自:https://blog.csdn.net/u010960184/article/details/82557978,并进行部分修改