Postgresql - 参数 session_replication_role

首先,为什么要记录这个参数。因为这个参数有可能影响着外键的使用。
session_replication_role,这个参数的意思是,在会话中的replication的role,角色有三个值,

  1. origin,源,也是官方推荐使用的值。
  2. local,本地。
  3. replica,从库。

官网对这个参数的解释:
Controls firing of replication-related triggers and rules for the current session. Setting this variable requires superuser privilege and results in discarding any previously cached query plans. Possible values are origin (the default), replica and local.
控制在当前会话,是否将replication相关的trigger和rule失效。

默认值为origin,这是不会有任何影响。
当值设置为local时,角色是本地,不存在主备的概念,所以也是不会有影响。
但是当值为replica时,角色是备,会禁用 replication-related 的 trigger 和 rule。

注意:
由于pg中,外键的本质就是trigger,所以当设置为repilca的时候,replication相关的会一同被禁用,所以现象为外键失效!

==================================================
实验:PG 9.6.11
当值为origin时。

-- 建主表
testdb=> create table test01 (id int primary key, col1 varchar(10));
CREATE TABLE
-- 建子表
testdb=> create table test02 (id int primary key, t1_id int);
CREATE TABLE
-- 建约束
testdb=> alter table test02 add constraint test02_t1_id_fkey foreign key (t1_id) references test01 (id) on delete cascade on update restrict ;
ALTER TABLE
-- 向主表插入值
testdb=> insert into test01 values (1,'a');
INSERT 0 1
-- 向子表插入值
testdb=> insert into test02 values (1,1);
INSERT 0 1
-- 向子表外键插入主表不存在的值,报错
testdb=>  insert into test02 values (2,2);a
ERROR:  insert or update on table "test02" violates foreign key constraint "test02_t1_id_fkey"
DETAIL:  Key (t1_id)=(2) is not present in table "test01".
-- 子表外键更新主表不存在的值,报错。
testdb=> update test02 set t1_id = 2 where t1_id = 1;
ERROR:  insert or update on table "test02" violates foreign key constraint "test02_t1_id_fkey"
DETAIL:  Key (t1_id)=(2) is not present in table "test01".
-- 主表主键更新,报错。
testdb=> update test01 set id = 2 where id = 1;
ERROR:  update or delete on table "test01" violates foreign key constraint "test02_t1_id_fkey" on table "test02"
DETAIL:  Key (id)=(1) is still referenced from table "test02".
-- 主表主键删除,成功,子表关联键一同删除。
testdb=> delete from test01 where id = 1;
DELETE 1
testdb=> select * from test02;
 id | t1_id
----+-------
(0 rows)

==================================================
当session_replication_role = replica时,

testdb=> show session_replication_role ;
 session_replication_role
--------------------------
 replica
(1 row)
--建主表
testdb=> create table test01 (id int primary key, col1 varchar(10));
CREATE TABLE
--建子表
testdb=> create table test02 (id int primary key, t1_id int);
CREATE TABLE
--建外键
testdb=> alter table test02 add constraint test02_t1_id_fkey foreign key (t1_id) references test01 (id) on delete cascade on update restrict ;
ALTER TABLE
-- 向主表插入值
testdb=> insert into test01 values (1,'a');
INSERT 0 1
-- 向子表插入值
testdb=> insert into test02 values (1,1);
INSERT 0 1
-- 向子表外键插入主表不存在的值,
testdb=> insert into test02 values (2,2);
INSERT 0 1
-- 子表外键更新主表不存在的值
testdb=> update test02 set t1_id = 11 where t1_id = 1;
UPDATE 1
-- 主表主键更新
testdb=> update test01 set id = 3 where id = 1;
UPDATE 1
-- 主表主键删除,成功,子表关联键不会删除
testdb=> update test01 set id = 2 where id = 3;
UPDATE 1
testdb=> delete from test01 where id = 2;
DELETE 1
所有操作均已成功,说明外键已失效。
查看外键,及外键trigger的状态。
testdb=> select * from pg_catalog.pg_constraint where conname = 'test02_t1_id_fkey';
      conname      | connamespace | contype | condeferrable | condeferred | convalidated | conrelid | contypid | conindid | confrelid | confupdtype | confdeltype | confmatchtype | conislocal | coninhcount | connoinherit | conkey | confke
y | conpfeqop | conppeqop | conffeqop | conexclop | conbin | consrc
-------------------+--------------+---------+---------------+-------------+--------------+----------+----------+----------+-----------+-------------+-------------+---------------+------------+-------------+--------------+--------+-------
--+-----------+-----------+-----------+-----------+--------+--------
 test02_t1_id_fkey |         2200 | f       | f             | f           | t            |    16429 |        0 |    16427 |     16424 | r           | c           | s             | t          |           0 | t            | {2}    | {1}
  | {96}      | {96}      | {96}      |           |        |
(1 row)
testdb=> select * from pg_catalog.pg_trigger where tgconstraint = (select oid from pg_catalog.pg_constraint pcon where conname = 'test02_t1_id_fkey');
 tgrelid |            tgname            | tgfoid | tgtype | tgenabled | tgisinternal | tgconstrrelid | tgconstrindid | tgconstraint | tgdeferrable | tginitdeferred | tgnargs | tgattr | tgargs | tgqual
---------+------------------------------+--------+--------+-----------+--------------+---------------+---------------+--------------+--------------+----------------+---------+--------+--------+--------
   16424 | RI_ConstraintTrigger_a_16435 |   1646 |      9 | O         | t            |         16429 |         16427 |        16434 | f            | f              |       0 |        | \x     |
   16424 | RI_ConstraintTrigger_a_16436 |   1649 |     17 | O         | t            |         16429 |         16427 |        16434 | f            | f              |       0 |        | \x     |
   16429 | RI_ConstraintTrigger_c_16437 |   1644 |      5 | O         | t            |         16424 |         16427 |        16434 | f            | f              |       0 |        | \x     |
   16429 | RI_ConstraintTrigger_c_16438 |   1645 |     17 | O         | t            |         16424 |         16427 |        16434 | f            | f              |       0 |        | \x     |
(4 rows)

这时,看到trigger中状态为O,意思为在session_replication_role = origin或local时生效。
Controls in which session_replication_role modes the trigger fires. O = trigger fires in “origin” and “local” modes, D = trigger is disabled, R = trigger fires in “replica” mode, A = trigger fires always。

那我们怎么让他强制生效呢。

  1. 对于系统自建的trigger(外键)不能改变。
testdb=> alter table test02 enable trigger all;
ERROR:  permission denied: "RI_ConstraintTrigger_c_16437" is a system trigger
  1. 自建一个trigger。
testdb=> select * from pg_trigger where tgname like '%test1101%' ;
 tgrelid |      tgname       | tgfoid | tgtype | tgenabled | tgisinternal | tgconstrrelid | tgconstrindid | tgconstraint | tgdeferrable | tginitdeferred | tgnargs | tgattr | tgargs | tgqual
---------+-------------------+--------+--------+-----------+--------------+---------------+---------------+--------------+--------------+----------------+---------+--------+--------+--------
   16597 | test1101_repl_trg |  16575 |     29 | O         | f            |             0 |             0 |            0 | f            | f              |       0 |        | \x     |
(1 row)

测试,trigger无效。

-- 更改为一直执行
testdb=> alter table test1101 enable always trigger test1101_repl_trg ;
ALTER TABLE

testdb=> select * from pg_trigger where tgname like '%test1101%';
 tgrelid |      tgname       | tgfoid | tgtype | tgenabled | tgisinternal | tgconstrrelid | tgconstrindid | tgconstraint | tgdeferrable | tginitdeferred | tgnargs | tgattr | tgargs | tgqual
---------+-------------------+--------+--------+-----------+--------------+---------------+---------------+--------------+--------------+----------------+---------+--------+--------+--------
   16597 | test1101_repl_trg |  16575 |     29 | A         | f            |             0 |             0 |            0 | f            | f              |       0 |        | \x     |
(1 row)

再测试,trigger成功执行

总结:

  1. 将 session_replication_role = replica 时,外键一定失效。
    建立的trigger 和 rule可根据需要设置是否enable。
  2. trigger 和 rule可设置什么时候起作用。
DISABLE TRIGGER [ trigger_name | ALL | USER ]
ENABLE TRIGGER [ trigger_name | ALL | USER ]
ENABLE REPLICA TRIGGER
ENABLE ALWAYS TRIGGER
DISABLE RULE rewrite_rule_name
ENABLE RULE rewrite_rule_name
ENABLE REPLICA RULE rewrite_rule_name
ENABLE ALWAYS RULE rewrite_rule_name
  1. event trigger 相同,默认为o,可设置为是否生效。或在r下生效。
    默认为oringin。则在 replica下可以删除。
testdb=> alter event trigger abort_drop enable always ;
ALTER EVENT TRIGGER
testdb=> drop table test02;
ERROR:  Command DROP Any Object is disabled
CONTEXT:  PL/pgSQL function abort_drop_command() line 3 at RAISE
发布了213 篇原创文章 · 获赞 7 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/chuckchen1222/article/details/104776791