数据库的并发控制
数据库的并发控制
zhangjianyf 发表于1年前
数据库的并发控制
  • 发表于 1年前
  • 阅读 15
  • 收藏 0
  • 点赞 0
  • 评论 0
摘要: Database基础理论

事务的定义

事务(Transaction)是构成单一逻辑工作单元的操作集合,要么完整地执行,要么完全不执行。不论发生何种情况,DBS必须保证事务能正确、完整地执行。

事务的ACID性质:

1.原子性(Atomicity)

 一个事务对数据库的所有操作,是一个不可分割的工作单元。这些操作要么全部执行,要么什么也不做

保证原子性是数据库系统本身的职责,有DBMS的事务管理子系统来实现。

2.一致性(Consistency)

 一个事务独立执行的结果,应保持数据库的一致性,即数据不会因事务的执行而遭受破会。

确保单个事务的一致性是编写事务的应用程序员的职责。在系统运行时,有DBMS的完整性子系统执行测试任务。

3.隔离性(Isolation)

        在多个事务并发执行时,系统应保证与这些事务先后单独执行时的结果一样,此时称事务达到了隔离性的要求。也就是在多个事务并发执行时,保证执行结果是正确的,如同单用户环境一样。

         隔离性是由DBMS的并发控制子系统实现的。

4.持久性(Durability)

          一个事务一旦完成全部操作后,它对数据库的所有更新应永久地反映在数据库中,不会丢失。即使以后系统发生故障,也是如此。

持久性有DBMS的恢复管理子系统实现的。

 

并发操作带来的问题

在多用户共享系统中,许多事务可能同时对同一数据进行操作(“并发操作”),此时可能会破坏数据库的完整性。这里的”并发”(Concurrent)是指在单处理机(一个CPU)上,利用分时方法实行多个事务同时做。

DBMS的并发控制子系统,就是负责协调并发事务的执行,保证数据库的完整性,同时避免用户得到不正确的数据。

即使每个事务单独执行时时正确的,但多个事务并发执行时,如果系统不加以控制,任会破坏数据库的一致性,或者用户读了不正确的数据。数据库的并发操作通常会带来如下几个问题:丢失更新问题、读脏数据问题、不可重复读问题、幻读

Ø  更新丢失(Lost Update)

当两个或多个事务选择同一行,然后基于最初选定的值更新该行,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题—最后的更新覆盖了由其他事务所做的更新。例如,两个编辑人员制作了同一文档的电子副本。每个编辑人员独立地更改其副本,然后保存更改后的更改。如果在一个编辑人员完成并提交事务之前,另一个编辑人员不能访问同一个文件,则可避免此问题。

Ø  脏读(Dirty Reads)

一个事务正在对一条记录做修改,在这个事务完成并提交前,这条记录的数据就处于不一致状态;这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些”脏”数据,并据此做进一步的处理,就会产生未提交的数据依赖关系,这种现象被形象地叫做”脏读”。

Ø  不可重复读(Non-Repeatable Reads)

一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了改变或某些记录已经被删除了!这种现象就叫做”不可重复读”。

Ø  幻读(Phantom Reads)

一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为”幻读”。

1.       丢失更新问题

在表1-1中,数据库中A的初值是100,事务T1对A的值减30,事务T2对A的值增加1倍。如果执行次序是先T1后T2,那么结果A的值是140.如果是先T2后T1,那么A的值是170。这两种情况都应该是正确的。但是按表中的并发执行,结果A的值是200,这个值肯定是错误的,因为在时间t7丢失了事务T1对数据库的更新操作。因而这个并发操作是不正确的。

表1-1 在时间t7丢失了事务T1的更新

(FIND 表示从DB中读值,UPD表示把值写回到DB)

时间

更新事务T1

数据库中A的值

更新事务T2

t0

 

100

 

t1

FIND A

 

 

t2

 

 

FIND A

t3

A:=A-30

 

 

t4

 

 

A:=A*2

t5

UPD A

 

 

t6

 

70

UPD A

t7

 

200

 

 

2.       读脏数据问题

这里有两种情况,用两个例子说明。

2.1 (用户读了脏数据”,但没有破坏数据库的完整性)

在表1-2中,事务T1把A的值修改为70,但尚未提交(即未做COMMIT操作),事务T2紧跟着读未提交的A值(70)。随后,事务T1做ROLLBACK操作,把A的值恢复为100。而事务T2仍在使用被撤销了的A值70。在数据库技术中,把未提交的随后被撤销的数据称为”脏数据”。

表1-2 事务T2在时间t4读了未提交的A值

(FIND 表示从DB中读值,UPD表示把值写回到DB)

时间

更新事务T1

数据库中A的值

更新事务T2

t0

 

100

 

t1

FIND A

 

 

t2

A:=A-30

 

 

t3

UPD A

 

 

t4

 

70

FIND A

t5

*ROLLBACK*

 

 

t6

 

100

 

 

2.2   (用户读了脏数据,引起自身的更新操作被丢失,破坏了数据库的完整性)

在表1-2中,只是用户读了不正确的数据,而没有破坏数据库的完整性。但是表1-3的情况更糟,事务T2不仅在时间t4读了未提交的A值(70),而且实际上在时间t8还丢失了自己的更新操作。此时破坏了数据库的完整性。

表1-3 事务T2在时间t4读了未提交的A值,并在时间t8丢失了自己的更新

(FIND 表示从DB中读值,UPD表示把值写回到DB)

时间

更新事务T1

数据库中A的值

更新事务T2

t0

 

100

 

t1

FIND A

 

 

t2

A:=A-30

 

 

t3

UPD A

 

 

t4

 

70

FIND A

t5

 

 

A:=A*2

t6

 

 

UPD A

t7

 

140

 

t8

*ROLLBACK*

 

 

t9

 

100

 

 

3.       不可重复读问题

表1-4表示T1需要两次读取同一数据项A,但是在两次读操作的间隔中,另一个事务T2改变了A的值。因此,T1在两次读同一数据项A时却读出了不同的值。

表1-4事务T1两次读取A的值,却得到了不同的结果

(FIND 表示从DB中读值,UPD表示把值写回到DB)

时间

更新事务T1

数据库中A的值

更新事务T2

t0

 

100

 

t1

FIND A

 

 

t2

 

 

XFIND A

t3

 

 

A:=A*2

t4

 

 

UPD A

t5

 

200

COMMIT

t6

FIND A

 

 

 

这些问题都需要并发控制子系统来解决。譬如对于表1-1的丢失更新问题通常采用封锁(locking)技术加以解决:

1)         在时间t2应避免事务T2执行FIND操作。因为此时事务T1已读了A值,将要执行更新。或者

2)         在时间t5应避免事务T1执行UPD操作。因为事务T2已在使用A值。

 

(Lock)是一个与数据项相关的变量,对可能应用于该数据项上的操作而言,锁描述了该数据项的状态。

通常在数据库中每个数据项都有一个锁。锁的作用是使并发事务对数据库中数据项的访问能够同步。封锁技术中主要有两种封锁:排他型封锁(Exclusive Lock)【写锁】和共享型封锁(Shard Lock)【读锁】

Ø  排他型封锁(X锁)

如果事务T对某个数据R(可以是数据项、记录、数据集乃至整个数据库)实现了X锁,那么在T对数据R解除封锁之前,不允许其他事务T再对该数据加任何类型的锁。这种锁称为”X 锁”

 使用X锁技术,可以解决表1-1的丢失更新问题。如何表1-5所示。事务T1先对A实现X锁,更新A值后,在COMMIT之后,事务T2再重新执行”XFIND A”操作,并对A进行更新(此时A已是事务T1更新过的值)。这样就能得出正确的结果。

表1-5等事务T1更新完成后再执行事务T2

时间

更新事务T1

数据库中A的值

更新事务T2

t0

 

100

 

t1

XFIND A

 

 

t2

 

 

XFIND A(失败)

 

 

 

wait(等待)

t3

A:=A-30

 

wait

t4

 

 

wait

t5

UPD A

 

wait

t6

 

70

wait

t7

COMMIT(包括解锁)

 

wait

t8

 

 

XFIND A(重做)

t9

 

 

A:=A*2

t10

 

 

UPD A

t11

 

140

COMMIT(包括解锁)

 

Ø  共享型封锁(S锁)

采用X锁的并发控制度低,只允许一个事务独锁数据。而其他申请封锁的事务只能去排队去等。为此,降低要求,允许并发的读,就引入了共享型封锁(Shared Lock),这种锁简称为S 锁,又称为读锁。

定义:如果事务T对某数据加上S锁后,仍允许其他事务再对该数据加S锁,但在对该数据的所有S锁都解除之前决不允许任何事务对该数据加X锁。

 

使用S锁的操作有三个:

l  申请S锁操作”SFIND R”:表示事务对数据R申请加S锁,若成功,则可以读数据R,但不可以写数据R;若不成功,那么这个事务将进入等待队列,一直到获准S锁,事务才能继续做下去。

l  升级和写操作”UPDX R”:表示事务要把对数据R的S锁升级为X锁,若成功则更新数据R,否则这个事务进入等待队列。

l  解除S锁操作”SRELEASE R”:表示事务要解除对数据R的S锁。

   可以看出,获准S锁的事务只能读数据,不能更新数据,若要更新,则先要把S锁升级为X锁。另外,由于S锁只允许读数据,因此解除S锁的操作不必非要合并到事务的结束操作中去,可以随时根据需要解除S锁。

  使用S锁技术,也可以解决表1-1的丢失更新问题,但有可能出现表1-6所示的那种情况。也就是S锁解决了丢失更新问题,但同时又可能会引起另外一个问题-死锁。

表1-6更新未丢失,但在时间t6发生了死锁

时间

更新事务T1

数据库中A的值

更新事务T2

t0

 

100

 

t1

SFIND A

 

 

t2

 

 

SFIND A

t3

A:=A-30

 

 

t4

 

 

A:=A*2

t5

UPDX A(失败)

 

wait

t6

wait

 

UPDX A(失败)

t7

wait

 

wait

t8

wait

 

wait

 

 

事务的存取模式

  SQL2允许事务有两种模式:

1.         READ ONLY(只读型):事务对数据库的操作只能是读操作。定义这个模式后,表示随后 的事务均是只读型。

2.         READ WRITE(读写型):事务对数据库的操作可以是读操作,也可以是写操作。定义这个模式后,表示随后的事务均是读写型。在程序开始时默认这种模式。

事务的隔离级别

 SQL2提供事务的四种隔离级别让用户选择。这四个级别从高到低如下所述:

1.SERIALIZABLE(可串行化):允许事务与其他事务并发执行,但系统必须保证并发调度室可串行化,不致发生错误。在程序开始时默认这个级别。

2.REPEATABLE READ(可重复读)只允许事务读已提交的数据,并且在两次读同一数据时不允许其他事务修改此数据。

3.READ COMMITTED(读提交数据)允许事务读已提交的数据,但不要求”可重复读”。例如,事务对同一记录的两次读取之间,记录可能已经被提交的事务更新。

4.READ UNCOMMITTED(可以读未提交数据)允许事务读已提交或未提交的数据。这时SQL2中所允许的最低一致性级别。

上述四种级别可以用下列SQL语句定义:

SET TRANSACTIONN ISOLATION LEVEL SERIALIZABLE

SET TRANSACTIONN ISOLATION LEVEL REPEATABLE READ

SET TRANSACTIONN ISOLATION LEVEL READ COMMITTED

SET TRANSACTIONN ISOLATION LEVEL READ UNCOMMITTED

 

4种隔离级别比较

读数据一致性及允许的并发副作用

隔离级别

读数据一致性

脏读

不可重复读

幻读

未提交读

最低级别,只能保证不读取物理上损坏的数据

已提交读

语句级

可重复读

事务级

可序列化

最高级别,事务级

 

共有 人打赏支持
粉丝 2
博文 20
码字总数 15543
×
zhangjianyf
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: