详细说明数据库并发访问时会出现哪些问题?并可以通过什么方法解决?
数据库的并发访问会引起丢失修改、不可重复读和读“脏”数据3种问题。
丢失修改是指一事务的修改数据尚未提交,而另一事务又将该未提交修改的数据做了再次修改。例如,两个编辑人员制作了同一文档的电子复本。每个编辑人员独立地更改其复本,然后保存更改后的复本,这样就覆盖了原始文档。最后保存其更改复本的编辑人员覆盖了第一个编辑人员所做的更改。
不可重复读是指事务T1读取数据后,事务T2执行更新操作,是T1无法再现前一次读取结果。例如,一个编辑人员两次读取同一文档,但在两次读取之间,作者重写了该文档。当编辑人员第二次读取文档时,文档已更改。原始读取不可重复。
读“脏”数据是指事务T1修改某一数据,并将其写回磁盘,事务T2读取同一数据后,T1由于某种原因被撤销,这是T1已修改过的数据恢复原始值,T2读到的数据就与数据库中的数据不一致,则T2读到的数据九位“脏”数据,即不正确的数据。例如,一个编辑人员正在更改电子文档。在更改过程中,另一个编辑人员复制了该文档(该复本包含到目前为止所做的全部更改)并将其分发给预期的用户。此后,第一个编辑人员认为目前所做的更改是错误的,于是删除了所做的编辑并保存了文档。分发给用户的文档包含不再存在的编辑内容,并且这些编辑内容应认为从未存在过。
为避免并行事务操作出现上述问题,DBMS在进行并发控制时,为保证事务的可串行化执行,采用了基于锁的并发控制协议。
所谓封锁就是事务T再多某个数据对象操作之前,先向系统发出请求,对其加锁。加锁后事务T就对该数据有了一定的控制,在事务T释放它的锁之前,其它的事务不能更新次数据的对象。
基本的封锁类型有两种:排他锁和共享锁。
例如:
设table1(A,B,C)
A B C
a1 b1 c1
a2 b2 c2
a3 b3 c3
1)排它锁
新建两个连接
在第一个连接中执行以下语句
begin tran
update table1
set A='aa'
where B='b2'
waitfor delay '00:00:30' --等待30秒
commit tran
在第二个连接中执行以下语句
begin tran
select * from table1
where B='b2'
commit tran
若同时执行上述两个语句,则select查询必须等待update执行完毕才能执行即要等待30秒
2)共享锁
在第一个连接中执行以下语句
begin tran
select * from table1 holdlock -holdlock
where B='b2'
waitfor delay '00:00:30'
commit tran
在第二个连接中执行以下语句
begin tran
select A,C from table1
where B='b2'
update table1
set A='aa'
where B='b2'
commit tran
若同时执行上述两个语句,则第二个连接中的select查询可以执行
而update必须等待第一个连接中的共享锁结束后才能执行 即要等待30秒