PostgreSQL
通过使用称为
MVCC
(多版本并发控制)的方法实现并发控制。在此方法中,
当正在更新项目时,更改将不会覆盖原始数据,而是将创建项目的新版本(带有更改)。
因此,我们将存储多个版本的项目。这种模型的主要优点之一是为查询(读取)数据而获
取的锁与写入数据时获取的锁不冲突,因此读取永远不会阻止写入
,
写入也从不阻止读取。
但是,如果存储了同一项目的多个版本,那么事务看到的是哪个版本呢?这里需要回顾一
下事务隔离的概念。事务指定隔离级别,该级别定义一个事务必须与其他事务所做的资源
或数据修改隔离的程度。该程度与事务生成的锁直接相关,因此,它可以在事务级别进行
指定,而且可以确定正在运行的事务对其他正在运行的事务的影响。
为什么在处理死锁问题时会涉及以上内容呢?因为
sql
命令会自动获取锁以确保
MVCC
行
为,并且获取的锁类型取决于定义的事务隔离级别。理解各种类型的锁之间的冲突是非常
重要的,这是因为两个事务不能同时在同一个对象上持有冲突的锁。还有一个值得注意的
细节是,一旦获得锁通常会一直持有到事务结束。当有两个想要同时在同一个对象上持有
冲突锁的运行中的事务时会发生什么?其中一个将获得锁定,另一个将不得不等待。
什么是死锁?
数据库死锁有很多种定义,但简而言之就是:数据库死锁是两个或多个事务正在等待彼此
释放锁的情况。
例如,以下情况将导致死锁的发生:
应用程序
A
获取表
1
第
1
行的锁来进行更新操作。与此同时,应用程序
B
获得表
2
第
2
行
的锁。现在,应用程序
A
需要锁定表
2
第
2
行,来继续执行并完成事务,但它无法获取锁,
这是因为该锁现在由应用程序
B
保持。应用程序
A
需要等待应用程序
B
释放它。而且,如
果应用程序
B
需要锁定表
1
第
1
行,来继续执行并完成事务,它也无法获取锁,因为该锁
由应用程序
A
持有。
这样我们就遇到了死锁。应用程序
A
正在等待应用程序
B
持有的资源来完成运行,而应用
程序
B
正在等待应用程序
A
持有的资源。那么这种情况下将如何继续呢?数据库引擎将检
测死锁并终止其中一个事务,解除阻塞另一个事务并在被杀死的事件上引发死锁错误。
如何预防死锁?
在数据库方面能做出避免死锁的事情并不多。不过还是可以给出一些建议:
1
)搜索长时间运行的事务。由于锁通常保持到事务结束,因此事务处理的时间越长,对
资源的锁定就越长。如果可能,尝试将长时间运行的事务拆分为更小
/
更快的事务。
2
)有时不可能实际拆分事务,因此工作应该集中于每次都尽量以一致的顺序执行操作,
这样事务就能形成格式良好的队列并且不会发生死锁。
3
)建议将重试逻辑添加到应用程序中,如果发生死锁,应用程序将再次运行相同的命令。
评论