设为首页 收藏本站
查看: 2062|回复: 0

[经验分享] PostgreSQL中如何对应SQL Server中的rowversion

[复制链接]

尚未签到

发表于 2016-12-21 10:29:14 | 显示全部楼层 |阅读模式
SQL Server中有个rowversion,利用它可以实现乐观锁策略的并发更新。那么在PostgreSQL中有没有类似的东西呢?

PostgreSQL中,最接近rowversion的就是系统隐藏列xmin。而且在hibernate的PostgreSQL方言中,也是使用xmin作为行版本的标识使用。

xmin是插入该行版本的事务标识(事务ID)。PostgreSQL每次更新行都会创建一个新的行版本,所以如果其他事务修改了之前看到的记录,那么这条记录的xmin必然会变更。



  • postgres=# create table tb1(id int,name text);

  • CREATE TABLE
  • postgres=# insert into tb1 values(1,'a');
  • INSERT 0 1
  • postgres=# update tb1 set name='b' where id=1;
  • UPDATE 1
  • postgres=# select xmin,* from tb1;
  • xmin | id | name
  • -------+----+------
  • 55815 | 1 | b
  • (1 row)

但是使用xmin作为行版本标识不能区别同一个事务内的两次修改。



  • postgres=# begin;

  • BEGIN
  • postgres=# update tb1 set name='c' where id=1;
  • UPDATE 1
  • postgres=# select xmin,* from tb1;
  • xmin | id | name
  • -------+----+------
  • 55819 | 1 | c
  • (1 row)

  • postgres=# update tb1 set name='c' where id=1;
  • UPDATE 1
  • postgres=# select xmin,* from tb1;
  • xmin | id | name
  • -------+----+------
  • 55819 | 1 | c
  • (1 row)

  • postgres=# end;
  • COMMIT

不过,其实我们不需要为这个小小的瑕疵担心。
因为,事务内的第一次修改对其他事务不可见,唯一能看见它的只有修改这一行的事务自己。如果认为事务自己的第二次修改和自己的第一次修改冲突是不是有点荒谬。所以我们可以认为事务的第二次修改覆盖第一次修改是应用自己愿意。

好了,还真有钻牛角尖的。以上的差异毕竟导致了和SQL Server的rowversion的行为上的微不足道的差异,但为了避免在解释这种差异上多费口舌,我们试图找一种和SQL Server完全一致的方案。

首先我们想到了xmin+cmin。cmin代表了插入事务内部的命令标识。xmin+cmin的组合不就完美了吗。
先不考虑,组合两个字段作为行版本标识在使用上的不便,这个方法还有很大的漏洞。
因为在PostgreSQL内部,cmin和cmax使用的是共用的同一个存储域,就好像C语言中的联合。所以更新和删除操作也会修改cmin。
下面这个例子中一个回滚的更新修改了cmin,如果把cmin作为行版本号一部分使用,就会误判断为发生更新冲突了。




  • postgres=# select xmin,cmin,cmax,* from tb1;

  • xmin | cmin | cmax | id | name
  • -------+------+------+----+------
  • 55822 | 0 | 0 | 1 | c
  • (1 row)

  • postgres=# begin;
  • BEGIN
  • postgres=# insert into tb1 values(2,'a');
  • INSERT 0 1
  • postgres=# update tb1 set name='d' where id=1;
  • UPDATE 1
  • postgres=# rollback;
  • ROLLBACK
  • postgres=# select xmin,cmin,cmax,* from tb1;
  • xmin | cmin | cmax | id | name
  • -------+------+------+----+------
  • 55822 | 1 | 1 | 1 | c
  • (1 row)

除此以外,还有一个候选是ctid。但是每次VACUUM FULL之后, 一个行的ctid都会被更新或者移动。所以如果能够容忍VACUUM FULL带来的更新冲突的误判断,也可以考虑。

转了一圈,最后我还是认为xmin是作为行版本号的最佳方案。


参考:
关于PostgreSQL中的几个系统隐藏列,可参考手册
http://58.58.27.50:8079/doc/html/9.3.1_zh/ddl-system-columns.html
------------------------------------------------------------------------
5.4. 系统字段
每个表都有几个系统字段,这些字段是由系统隐含定义的。因此, 这些名字不能用于用户定义的字段名。请注意这些限制与这个名字是否关键字无关, 把名字用引号括起来并不能让你逃离这些限制。你实际上不需要注意这些字段; 只要知道它们存在就可以了。



oid  行对象标识符(对象ID)。这个字段只有在创建表的时候使用了WITH OIDS 或者是配置参数default_with_oids的值为真时出现。 这个字段的类型是oid(和字段同名);参阅Section 8.18获取有关这种类型的更多信息。
tableoid  包含本行的表的OID。这个字段对那些从继承层次中选取的查询特别有用(参阅Section 5.8), 因为如果没有它的话,我们就很难说明一行来自哪个独立的表。tableoid 可以和pg_class的oid字段连接起来获取表名字。
xmin  插入该行版本的事务标识(事务ID)。注意:在这个环境里,一个行版本是一行的一个状态; 一行的每次更新都为同一个逻辑行创建一个新的行版本。
cmin  在插入事务内部的命令标识(从零开始)。
xmax  删除事务的标识(事务ID),如果不是被删除的行版本,那么是零。在一个可见行版本里, 这个字段有可能是非零。这通常意味着删除事务还没有提交,或者是一个删除的企图被回滚掉了。
cmax  删除事务内部的命令标识符,或者是零。
ctid  一个行版本在它所处的表内的物理位置。请注意,尽管ctid 可以用于非常快速地定位行版本,但每次VACUUM FULL之后, 一个行的ctid都会被更新或者移动。因此ctid 是不能作为长期的行标识符的。应该使用 OID ,或者更好是用户定义的序列号,来标识一个逻辑行。
------------------------------------------------------------------------

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-317318-1-1.html 上篇帖子: ChinaUnix博客 下篇帖子: PostgreSQL 事务模型介绍
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表