我一直在阅读Postgres中关于可序列化事务的很多内容,但遇到了一个我无法解决的问题。假设我有两个来自不同psql进程的Postgres会话A和B,并且在开始任何事务之前,我创建了角色role1
和role2
myuser=# CREATE ROLE role1 ;
CREATE ROLE
myuser=# CREATE ROLE role2 ;
CREATE ROLE
此时,我可以通过myuser=# BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE ;
在两个会话中启动交易,并验证两个会话都通过SELECT * FROM pg_catalog.pg_roles;
假设我从会话B中删除角色role2
,验证它没有显示并提交:
myuser=# DROP ROLE role2 ;
DROP ROLE
myuser=# SELECT * FROM pg_catalog.pg_roles;
rolname | rolsuper | rolinherit | rolcreaterole | rolcreatedb | rolcanlogin | rolreplication | rolconnlimit | rolpassword | rolvaliduntil | rolbypassrls | rolconfig | oid
-----------------------------------------------+----------+------------+---------------+-------------+-------------+----------------+--------------+-------------+---------------+--------------+-----------+-------
role1 | f | t | f | f | f | f | -1 | ******** | | f | | 16563
myuser=# commit ;
COMMIT
现在,让我们回到会议A:
即使在删除role2
并在会话B内部提交之后,我们仍然可以看到会话A中的事务仍然看到两个角色(正如预期的那样,因为这是可序列化的):
myuser=# SELECT * FROM pg_catalog.pg_roles;
rolname | rolsuper | rolinherit | rolcreaterole | rolcreatedb | rolcanlogin | rolreplication | rolconnlimit | rolpassword | rolvaliduntil | rolbypassrls | rolconfig | oid
-----------------------------------------------+----------+------------+---------------+-------------+-------------+----------------+--------------+-------------+---------------+--------------+-----------+------
role1 | f | t | f | f | f | f | -1 | ******** | | f | | 16563
role2 | f | t | f | f | f | f | -1 | ******** | | f | | 16564
现在,让我们试试GRANT
命令。这是奇怪的部分:
myuser=# GRANT role2 TO role1 ;
ERROR: role "role2" does not exist
在运行GRANT
之前,我们可以看到role1
和role2
这两个角色都存在,但现在我们看到了这样的错误。那是为什么?
谢谢!
答案 0 :(得分:3)
对于“正常”(即非目录)表,这样的冲突操作会导致序列化错误。虽然可序列化事务看到数据库的旧状态,但任何修改已更改的值的尝试都会导致此类错误。
这种情况的不同之处在于存储角色和角色成员资格的表(pg_authid
和pg_auth_members
)是目录表(甚至共享目录因为角色适用于所有数据库),并且对于这些处理和错误消息略有不同。
即使错误消息令人惊讶,操作也会失败并且是必要的。