分享

数据库并发访问、事务与锁的关系

 xue_dong5437 2011-12-27

首先,让我们了解下什么是事务?事务是作为单个逻辑单元工作执行的一系列操作。可以是一条 sql 语句,也可以是多条 sql 语句 ( 这是它的描述性定义 ) 

II 事务的特性:

1 )原子性 (Atomic) :指整个数据库事务是不可分割的工作单位。

2 )一致性 (Consistency) :指数据库事务不能破坏关系数据的完整性以及业务逻辑的一致性。

3  隔离性 (Isolation) :指的是在并发环境中,当不同的事务同时操作相同的数据时,每个事务都有各自的完整数据空间。

4  持久性 (Durability) :指的是只要事务成功结束,它对数据库所做的更改就必须永久保存下来。

数据库采用日志来保证事务的原子性,一致性和持久性,日志记录了事务对数据库所做的更新,如果某个事务在执行过程中发生错误,就可以根据日志,撤销事务对数据库已做的更改,使数据库退回到执行事务前的初始状态。

数据库使用锁机制来保证事务的隔离性,拥有各自独立的空间。

事务具有这四个特征是什么意思呢?是不是说作为一个事务必须具有这四个特性才成为事务或者就不是事务呢?本人是这样认为的,事务必须有原子性、一致性和持久性三个特征,而隔离性则根据实际的需要确定隔离的程度和隔离的级别(正是基于此才引出后面的事务的隔离级别)。

  III . 事务的隔离级别

1 、数据库事务的隔离级别:四种

隔离级别

脏读( Dirty Read 

写覆盖( Write Cover 

不可重复读( NonRepeatable Read 

幻读( Phantom Read 

读未提交( Read uncommitted 

可能

可能

可能

可能

读已提交( Read committed 

不可能

可能

可能

可能

可重复读( Repeatable read 

不可能

 

不可能

可能

可串行化( Serializable 

不可能

 

不可能

不可能

 

那么事务的隔离级别与锁有什么关系呢?本人认为事务的隔离级别是通过锁的机制实现的,事务的隔离级别是数据库开发商根据业务逻辑的实际需要定义的一组锁的使用策略。当我们将数据库的隔离级别定义为某一级别后如仍不能满足要求,我们可以自定义 sql 的锁来覆盖事务隔离级别默认的锁机制。

读取未提交( Read Uncommitted)

这是最低的事务隔离级别,读事务不会阻塞读事务和写事务,写事务也不会阻塞读事务,但是会阻塞写事务。这样造成的一个结果就是当一个写事务没有提交的时候,读事务照样可以读取,那么造成了脏读的现象。

读取已提交 (Read Committed)

采用此种隔离界别的时候,写事务就会阻塞读事务和写事务,但是读事务不会阻塞读事务和写事务,这样因为写事务会阻塞读取事务,那么从而读取事务就不能读到脏数据 ,但是因为读事务不会阻塞其它的事务,这样还是会造成不可重复读的问题

可重复读( Repeatable Read)

采用此种隔离级别,读事务会阻塞写事务 ,但是读事务不会阻塞读事务,但是写事务会阻塞写事务和读事务 。因为读事务阻塞了写事务,这样以来就不会造成不可重复读的问题,但是这样还是不能避免幻影读问题。

序列化( serializable)

此种隔离级别是最严格的隔离级别,如果设置成这个级别,那么就不会出现以上所有的问题(脏读,不可重复读,幻影读)。但是这样以来会极大的影响到我们系统的性能,因此我们应该避免设置成为这种隔离级别。

在实践中,我们一般采用读取已提交或者更低的事务隔离级别,配合各种并发访问控制策略来达到并发事务控制的目的。

二、锁

MySQL  InnoDB 有两种模式的行锁:

1 )共享锁:允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。

    ( Select * from table_name where ......lock in share mode)

2 )排他锁:允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和   排他写锁。 (select * from table_name where.....for update)

     为了允许行锁和表锁共存,实现多粒度锁机制;同时还有两种内部使用的意向锁(都是表锁),分别为意向共享锁和意向排他锁。

InnoDB 行锁是通过给索引项加锁来实现的,即只有通过索引条件检索数据, InnoDB 才使用行级锁,否则将使用表锁!

三、并发控制

当许多人试图同时修改数据库中的数据时,必须实现一个控制系统,使一个人所做的修改不会对其他人产生负面影响,这成为并发控制,并发控制有两种类型:

乐观并发控制和悲观并发控制。

乐观并发控制:

乐观锁:

基本思想:每次提交一个事务更新时,我们先看看要修改的东西从上次读取以后有没有被修改过,如果修改过,那么更新就会失败。

乐观锁其实并不会锁定任何记录,所以如果我们数据库的事务隔离级别设置为读取已提交或者更低的隔离界别,那么是不能避免不可重复读问题的(因为此时读事务不会阻塞其它事务),所以采用乐观锁的时候,系统应该要容许不可重复读问题的出现。

乐观锁的实现策略

版本 (Version) 字段:在我们的实体中增加一个版本控制字段,每次事务更新后就将版本字段的值加 1.

时间戳 (timestamps): 采取这种策略后,当每次要提交更新的时候就会将系统当前时间和修改时间。

悲观锁也就是上面讲到的我们认为的通常意义上的锁 。

以上有些是本人的一些愚见!大家感觉有什么不对的,欢迎指出愿和大家一起交流共同进步!

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多