关键词不能为空

当前您在: 主页 > 英语 >

chewPostgreSQL串行化访问隔离级别分析

作者:高考题库网
来源:https://www.bjmy2z.cn/gaokao
2021-01-28 14:53
tags:

chew-hjc

2021年1月28日发(作者:excited)



1,


SERIALIZABLE

< p>
隔离级别介绍



SERIALIZABLE


事务隔离级别,中文叫串行化,他是


postgresql

< p>
事务级别中最高一级,


postgresql


默认 事务隔离级别是


read committed,


不过这个可以 通过配置



中的


default_tra nsaction_isolation


参数来设置默认事务隔离级别,采用

< p>
SERIALIZABLE


事务隔离


级别可以防止 脏读(


dirty read



,非重 复读(


nonrepeatable read



,和幻像(


phantom read




一个事务如果进入了


set traansaction isolation level serializ able;


就会独占这个事务需要的所有


资源,其他任何修改同 样资源的请求都会被推出,不过讲述


postgresql


事务 隔离级别


SERIALIZABLE


的特性时是必需要结合


postgresql


的另一个实现机制


M VCC(


多版本控制



Multiversion Concurrency Control, MVCC)


一起来说明。




SQL


标准定义了四种隔离级别。最严格的是可序列化,在标准中用了一 整段来定义它,其中


说到一组可序列化事务的任意并发执行被保证效果和以某种顺序一个 一个执行这些事务一


样。


其他三种级别使用并发事务之间交互产 生的现象来定义,


每一个级别中都要求必须不出


现一种现象。< /p>


注意由于可序列化的定义,


在该级别上这些现象都不可能发生


(这并不令人惊



--

如果事务的效果与每个时刻只运行一个的相同,你怎么可能看见由于交互产生的现


象 ?)。



在各个级别上被禁止出现的现象是:



脏读(


dirty read



:当一个事务读取另一个事务尚未提交的修改时数据就叫脏读




非重复读(


nonrepeatable

read



:同一查询在同一事务中多次进行,由于其他提 交事务所做


的修改或删除,如果每次返回不同的结果集,就叫非重复读。




幻像



phantom read




同一查询在同一事务中多次进行,


由于其他提交事务所做的插入操作,


每次返回不同的结果集,就叫幻 像读。




13-1.

< p>
标准


SQL


事务隔离级别



隔离级别



脏读



不可重复读



幻读



读未提交



可能



可能



读已提交



不可能



可能



可重复读



不可能



不可能



可序列化



不可能



不可能







可能



可能



可能



不可能



PostgreSQL


官方文档介绍:



/docs/9.5/#XACT-SERIALIZABLE




13.2.1.


读已提交隔离级别



读已提交



PostgreSQL


中的默认隔离级别。< /p>



当一个事务运行使用这个隔离级别时,



一个


查询(没有


FOR


UPDATE/SHARE


子句)只能看到查询开始之前已经被提交的数据,



而无法看


到未提交的数据或在查询执 行期间其它事务提交的数据。实际上,


SELECT


查询看到的 是一


个在查询开始运行的瞬间该数据库的一个快照


。不过


SELECT


可以看见在它自身事务中之前


执 行的更新的效果,


即使它们还没有被提交。


还要注意的是,


即使在同一个事务里两个相邻



SELEC T


命令可能看到不同的数据,



因为其 它事务可能会在第一个


SELECT


开始和第二个


SELECT


开始之间提交





13.2.2.


可重复读隔离级别



可重复读


隔离级别只看到在事务开始之前被提交的数据;


它从来看不到未提交的数 据或者并


行事务在本事务执行期间提交的修改(不过,查询能够看见在它的事务中之前执 行的更新,


即使它们还没有被提交)



这是比


SQL


标准对此隔离级别所要求的更强的保证,


并且阻止




13-1


中描述的所有现象。如上面所提到的,这是标准特别允许的,标准只描述了每种隔离


级别必须提供的


最小


保护。



这个级别与读已提交不同之处在于,


一个可重复读 事务中的查询可以看见在


事务


开始时的一


个快照,而不是事务中当前查询开始时的快照。因此,在一个


单一

事务中的后续


SELECT



令看 到的是相同的数据,即它们看不到其他事务在本事务启动后提交的修改。



使用这个级别的应用必须准备好由于序列化失败而重试事务。



UPDATE



DELETE



SELECT FOR UPDATE



SELECT FOR SHARE

< p>
命令在搜索目标行时的行为和


SELECT


一样:



它们将只找到在事务开始时已经被提交的行。



不过,在被找到时,这样的


目标行可能已经被其它并发事务更新(或删除或锁住 )。在这种情况下,



可重复读事务将


等待第一个更新事务提交或者回滚(如果它还在进行中)。



如 果第一个更新事务回滚,那


么它的作用将被忽略并且可重复读事务可以继续更新最初发现 的行。



但是如果第一个更新


事务提交 (并且实际更新或删除该行,而不是只锁住它)


,则可重复读事务将回滚并带有如


下消息



ERROR: could not serialize access due to concurrent update


因为一个可重复读事务无法修改或者锁住被其他在可重复读事务开始之后的事务改变的行。



当一个应用接收到这个错误消息,


它应该 中断当前事务并且从开头重试整个事务。


在第二次


执行中,


该事务将见到作为其初始数据库视图一部分的之前提交的改变,


这样 在使用行的新


版本作为新事务更新的起点时就不会有逻辑冲突。



注意只有更新事务可能需要被重试;只读事务将永远不会有序列化冲突。



可重复读模式提供了一种严格的保证,


在其中每一 个事务看到数据库的一个完全稳定的视图。


不过,


这个视图并不 需要总是和同一级别上并发事务的某些序列化


(一次一个)


执行 保持一


致。


例如,


即使这个级别上的一 个只读事务可能看到一个控制记录被更新,


这显示一个批处


理已 经被完成但是


不能


看见作为该批处理的逻辑组成部分的一个细节 记录,


因为它读取空值


记录的一个较早的版本。


如果不小心地使用显式锁来阻塞冲突事务,


尝试用运行在这个隔离


级别的事务来强制业务规则不太可能正确地工作。





2,


实例演示:



在数据库默认的读已提交隔离级别下:




会发生死锁问题:




如下图,两个用户


session< /p>


同时更新同一条记录时,


第二个


sess ion


需要等前一个更新提交或


回退之后,才能继续完成,如果 前一个用户


session


一直没有提交或回退,则会阻塞所有 其


他的


session


,直到发生超时 (若有设定


lock_timeout


的话)

< br>。通常情况下生产系统的异常


session


会阻塞部分 业务,需要手工


kill


进程的方式处理。







会发生更新丢失问题:




两个用户


session

< p>
同时更新同一条记录,第一个用户的更新,会被第二个用户覆盖,因为第


二 个用户无法得知当前记录已发生变化。如下图:



注:


更新丢失会影响的业务数据准确性,


如果更新的是银行卡账户余额,


则必须避免更新丢


失问题。




实例演示:








在数据库的可重复读隔离级别下:




可解决上例中的并行更新时更新丢失问题:




用户


A


和< /p>


B



session

同为可重复读级别,


A



B


用户先后(或同时)对同一条记录更新,


后更新的

session


会等待前一个


SQL


提交或回退,当回退时,第二个


session


会继续执行,


当提交时,第二个


session


会报 错“


could not serialize access due to concurrent update



,这种


保护机制会避免更新丢失的情况。



注:此时没有锁等 待时间,第二个


session


在即时检测到记录被更新时立刻 返回报错信息,


即使


A



B


更新的是不同字段,只要是同一记录也会出错。





3, XXX


生产系统问题重现:



以查明的 案例为例,其他可能发生此错误的场景与此类似,具有代表性:




Mobile App


接口调用时,同时调用


user_info & cart_detail


接口:



由于




us er_info



,


(


由于方法


current_user._get_default_image ()


的调用


)


会执行

< br>SQL




UPDATE


(738)



cart_detai l


中,会执行:



[


'r'


].write(cr, SUPERUSER_ID, , {


'last_website_so_id'


:


sale_order_id})



两者在并行处理时,会针对同一条


res_partner


记录 做更新:





返回异常结果:





Odoo Server


日志错误信息:




2016-11-10 17:06:18,447 73932 INFO demo_20161020 _db:


bad query: UPDATE



'UTC') WHERE id IN (738)



2016-11-10 17:06:18,447 73932 ERROR demo_20161020


_rt:


could not serialize access due to concurrent update



2016-11-10 17:06:18,447 73932 ERROR demo_20161020


_rt:


40001





4,


解决方案一:接口重复调用方式代码实现:


< br>根据



使用这个级别的应用必须准备好由于序列化失败而 重试事务



的官方提示,


新增重试


事务功能。




装 饰器


repeat_execute




参数:


count =


执行次数



说明:

当被装饰的方法出现串行化更新失败时,


对其执行指定次数的重复调用,

< p>
当其中某一


次调用成功执行时,终止重复执行并返回结果。




Class 40



Transaction Rollback



40000 transaction_rollback


40002 transaction_integrity_constraint_violation


40001 serialization_failure


40003 statement_completion_unknown


40P01 deadlock_detected




def


repeat_execu te(count=


1


):



def


decorator(func):


@



(func)



def


wrapper(*args, **kwargs):


v_first_call=func(*args,**kwargs)

chew-hjc


chew-hjc


chew-hjc


chew-hjc


chew-hjc


chew-hjc


chew-hjc


chew-hjc



本文更新与2021-01-28 14:53,由作者提供,不代表本网站立场,转载请注明出处:https://www.bjmy2z.cn/gaokao/579968.html

PostgreSQL串行化访问隔离级别分析的相关文章