网上资料笔记总结!!数据库事务并发问题,锁机制和对应的4种隔离级别

数据库事务并发问题

数据库的操作通常为写和读,就是所说的CRUD:增加(Create)、读取(Read)、更新(Update)和删除(Delete)。
事务就是一件完整要做的事情。
事务是恢复和并发控制的基本单位。
事务必须始终保持系统处于一致的状态,不管在任何给定的时间并发事务有多少。
事务在关系数据库中,一个事务可以是一条SQL语句,一组SQL语句或整个程序。是数据库中各种数据项的一个程序执行单元。
事务是用户定义的一个操作序列(多个表同时读写)。这些操作要么都做,要么都不做,是一个不可分割的工作单位。
事务通常是以BEGIN TRANSACTION开始,以COMMIT或ROLLBACK结束。
COMMIT:表示事务完成提交,即提交事务的所有操作,具体地说就是将事务中所有对数据库的更新写回到磁盘上的物理数据库中去,事务正常结束。
ROLLBACK:表示事务的回滚,即在事务运行的过程中发生了某种故障,事务不能继续进行,系统将事务中对数据库的所有以完成的操作全部撤消,滚回到事务开始的状态或设置的回滚点。

多个事务同时访问数据库时候,会发生下列5类问题,包括3类数据读问题(脏读,不可重复读,幻读),2类数据更新问题(第一类丢失更新,第二类丢失更新):

(http://blog.csdn.net/zhangzeyuaaa/article/details/46400419 该博文有具体例子)

1,脏读(dirty read)

A事务读取B事务尚未提交的更改数据,并在这个数据基础上操作。如果B事务回滚,那么A事务读到的数据根本不是合法的,称为脏读。在oracle中,由于有version控制,不会出现脏读。

2,不可重复读(unrepeatable read)

A事务读取了B事务已经提交的更改(或删除)数据。比如A事务第一次读取数据,然后B事务更改该数据并提交,A事务再次读取数据,两次读取的数据不一样。

3,幻读(phantom read)

A事务读取了B事务已经提交的新增数据。注意和不可重复读的区别,这里是新增,不可重复读是更改(或删除)。这两种情况对策是不一样的,对于不可重复读,只需要采取行级锁防止该记录数据被更改或删除,然而对于幻读必须加表级锁,防止在这个表中新增一条数据。

4,第一类丢失更新

A事务撤销时,把已提交的B事务的数据覆盖掉。这种错误会造成非常严重的后果。

5,第二类丢失更新

A事务提交时,把已提交的B事务的数据覆盖掉。这种错误会造成非常严重的后果。

对于第一类丢失更新第二类丢失更新问题对比分析:

第一类丢失更新

 A事务撤销时,把已经提交的B事务的更新数据覆盖了。这种错误可能造成很严重的问题,通过下面的账户取款转账就可以看出来:


时间


取款事务A


转账事务B


T1


开始事务


T2


开始事务


T3


查询账户余额为1000元


T4


查询账户余额为1000元


T5


汇入100元把余额改为1100元


T6


提交事务


T7


取出100元把余额改为900元


T8


撤销事务


T9


余额恢复为1000 元(丢失更新)

A事务在撤销时,“不小心”将B事务已经转入账户的金额给抹去了。

第二类丢失更新

A事务覆盖B事务已经提交的数据,造成B事务所做操作丢失:


时间


转账事务A


取款事务B


T1


开始事务


T2


开始事务


T3


查询账户余额为1000元


T4


查询账户余额为1000元


T5


取出100元把余额改为900元


T6


提交事务


T7


汇入100元


T8


提交事务


T9


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

上面的例子里由于支票转账事务覆盖了取款事务对存款余额所做的更新,导致银行最后损失了100元,相反如果转账事务先提交,那么用户账户将损失100元。

数据库事务并发问题---解决措施:锁机制--4种隔离级别

共享锁和排它锁

为了解决并发问题,数据库系统引入锁机制。

基本的封锁类型有两种: 排它锁(Exclusive locks 简记为X锁) 和 共享锁(Share locks 简记为S锁)。

  • 排它锁又称为写锁。若事务T对数据对象A加上X锁,则只允许T读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。这就保证了其它事务在T释放A上的锁之前不能再读取和修改A。
  • 共享锁又称为读锁。若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其它事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这就保证了其它事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。

封锁粒度

数据库中为了实现并发控制而采用封锁技术。

封锁对象的大小称为封锁粒度(Granularity)。

封锁的对象可以是逻辑单元,也可以是物理单元。以关系数据库为例子,封锁对象可以是这样一些逻辑单元:属性值、属性值的集合、元组、关系、索引项、整个索引项直至整个数据库;也可以是这样的一些物理单元:页(数据页或索引页)、物理记录等。

封锁协议与隔离级别

在运用 排他锁 和 共享锁 对数据对象加锁时,还需要约定一些规则,例如何时申请 排他锁 或 共享锁、持锁时间、何时释放等。称这些规则为封锁协议(Locking Protocol)。对封锁方式规定不同的规则,就形成了各种不同的封锁协议。不同的封锁协议对应不同的隔离级别。

一级封锁协议(对应read uncommited)

一级封锁协议是:事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放。事务结束包括正常结束(COMMIT)和非正常结束(ROLLBACK)。

一级封锁协议可防止丢失更新,并保证事务T是可恢复的。

在一级封锁协议中,如果仅仅是读数据不对其进行修改,是不需要加锁的,所以它不能保证可重复读和不读“脏”数据。

二级封锁协议(对应read commited)

二级封锁协议是:一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,读完后即可释放S锁(瞬间S锁)。

二级封锁协议除防止了丢失更新,还可进一步防止读“脏”数据。

三级封锁协议(对应reapetable read)

三级封锁协议是:一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放。

三级封锁协议除防止了丢失更新和不读‘脏’数据外,还进一步防止了不可重复读和覆盖更新。

四级封锁协议(对应serialization)

四级封锁协议是对三级封锁协议的增强,其实现机制也最为简单,直接对 事务中 所 读取 或者 更改的数据所在的表加表锁,也就是说,其他事务不能 读写 该表中的任何数据。这样五类并发问题都得以避免!

注:封锁协议和隔离级别并不是严格对应的。

ANSI SQL 92标准定义了4个等级的事务隔离级别:

READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ、SERIALIZABLE

SQL 92 推荐使用REPEATABLE READ 保证数据的读一致性。

查看MySQL的事务隔离级别:默认、全局和会话事务隔离级别:

SELECT @@tx_isolation;
SELECT @@global.tx_isolation; 
SELECT @@session.tx_isolation;

数据库事务的隔离级别有4种,由低到高分别为Read uncommitted 、Read committed 、Repeatable read 、Serializable

事务的隔离级别:
SQL的标准定义了4个隔离级别,设定一定的规则,限定事务内部的那些改变是可见的,那些是不可见的。低级别的事务一般会支持更高的并发处理,涉及更低的系统开销。
Read Uncommitted【读未提交数据】:允许所有事务读取未被其他事务提交的数据修改。会导致脏读、不可重复读和幻读的问题的出现。  
Read Committed【读已提交数据】:只允许事务读取已经被其他事务提交的数据修改。Oracle和sql server默认的级别,可以避免脏读,但不可重复读和幻读问题仍然会出现。
Repeatable Read【可重读】:是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。但幻读问题未解除。
Serializable【可串行化】:最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

下图为数据库各隔离级别涉及的问题:Yes为存在问题,No反之不存在事务并发冲突问题:

 乐观锁和悲观锁的区别

悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。

乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。

两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。

时间: 2024-10-12 12:50:53

网上资料笔记总结!!数据库事务并发问题,锁机制和对应的4种隔离级别的相关文章

事务的四种隔离级别和七种传播行为

很多人容易搞混不可重复读和幻读,确实这两者有些相似.但不可重复读重点在于update和delete,而幻读的重点在于insert. 避免不可重复读需要锁行就行 避免幻影读则需要锁表 如果使用锁机制来实现这两种隔离级别,在可重复读中,该sql第一次读取到数据后,就将这些数据加锁,其它事务无法修改这些数据,就可以实现可重复 读了.但这种方法却无法锁住insert的数据,所以当事务A先前读取了数据,或者修改了全部数据,事务B还是可以insert数据提交,这时事务A就会 发现莫名其妙多了一条之前没有的数

简述数据库事务并发机制

摘要: 事务是最小的逻辑执行单元,也是数据库并发控制的基本单位,其执行的结果必须使数据库从一种一致性状态变到另一种一致性状态.事务具有四个重要特性,即原子性(Atomicity).一致性(Consistency).隔离性 (Isolation)和持久性 (Durability).本文首先叙述了数据库中事务的本质及其四大特性(ACID)的内涵,然后重点介绍了事务隔离性的动机和内涵,并介绍了数据库为此所提供的事务隔离级别以及这些事务隔离级别能解决的事务并发问题.介于并发安全与并发效率的平衡,我们一般

数据库事务并发了解一下呗

看了两天Java源码,有点懵.今天翻了一波面试的交流贴,唉,看看各大公司出的那些生怕你通过的面试题.真是觉得自己前途一片昏暗,片昏暗,昏暗,暗... but,习还是要学的,从面试题里看到有问数据库并发问题的,之前上课明明学过数据库原理的,但是看着题目大脑还是一片空白,片空白,空白,白...都是之间学习不总结的坑 so,来吧,再学一遍,同时梳理总结一下.好记性不如烂笔头头头头头! 数据库事务的四大特性(ACID) 原子性(Atomicity):是指一个事务中包含的所有操作,要么全做,要么全不做.

数据库事务的悲观锁和乐观锁

转载出处:http://www.hollischuang.com/archives/934 在数据库的锁机制中介绍过,数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性. 乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段. 无论是悲观锁还是乐观锁,都是人们定义出来的概念,可以认为是一种思想.其实不仅仅是关系型数据库系统中有乐观锁和悲观锁的概念,像memcache.hibernate.tair

MYSQL数据库事务4种隔离级别及7种传播行为

事务的特性: 原子性:事务的不可分割,组成事务的各个逻辑单元不可分割. 一致性:事务执行的前后,数据完整性保持一致. 隔离性:事务执行不应该受到其他事务的干扰. 持久性:事务一旦结束,数据就持久化到数据库中. 查看/设置隔离级别 查看:SELECT @@tx_isolation  设置:set tx_isolation='xxx' 事务的隔离级别 如果不考虑隔离性,引发一些安全问题 隔离性:一个事务的执行,不应该受到其他事务的干扰. 脏读:一个事务读到了另一个事务未提交的数据,导致查询结果不一致

[转载] 数据库分析手记 —— InnoDB锁机制分析

作者:倪煜 InnoDB锁机制常常困扰大家,不同的条件下往往表现出不同的锁竞争,在实际工作中经常要分析各种锁超时.死锁的问题.本文通过不同条件下的实验,利用InnoDB系统给出的各种信息,分析了锁的工作机制.通过本文可以帮助大家了解InnoDB锁的基本原理,常见的冲突.死锁,以及对InnoDB事务日志信息的解读. 1. 索引基本原理 InnoDB主要使用行级锁(row lock),其行锁是通过在索引项上加锁而实现的,如果MySQL的执行计划没有用到索引,那么行锁也就无意义了,所以了解锁之前需要了

mysql 事务的四种隔离级别

MYSQL标准定义了4种隔离级别,用来限定事务内外的哪些改变是可见的,哪些是不可见的. 低的隔离级一般支持更高的并发处理,并拥有更低的系统开销. 隔离级别由低到高:Read Uncommitted < Read Committed < Repeatable Read < Serializable. 第一:READ UNCOMMITTED (读取未提交内容) 在该隔离级别,所有事务都可以看到其他未提交(commit)事务的执行结果. 本隔离级别很少用于实际应用,因为它的性能也不比其他级别好

Mongodb并发与锁机制

Mongodb并发与锁机制 1. MongoDB 使用的锁 MongoDB 使用的是"readers-writer"锁, 可以支持并发但有很大的局限性,当一个读锁存在,许多 读操作可以使用这把锁,然而, 当一个写锁的存在,一个单一的写操作会 exclusively 持有该锁,同时 其它读,写操作不能使用共享这个锁:举个例子,假设一个集合里有 10 个文档,多个 update 操作不能 并发在这个集合上,即使是更新不同的文档. 2. 锁的粒度 在 2.2 版本以前,mongod 只有全局

MySQL数据库中的四种隔离级别

原文:MySQL数据库中的四种隔离级别 事务的隔离性比想象的要复杂,在 SQL 标准中定义了四种级别的隔离级别.通常而言,较低级别的隔离通常可以执行更高的并发,系统的开销也更低 READ UNCOMMITTED 该级别为未提交读.在该级别中,事务中的修改即使没有提交,对其他事务也都是可见的.事务可以读取未提交的数据,这也被称为脏读.这个级别会导致很多的问题,从性能上来说,它不会比其他级别好太多,但缺乏其他级别的很多好处.除非真的有非常必要的理由,在实际应用中一般很少使用. READ COMMIT