系统管理函数

配置设置函数

查询当前的配置
testdb=# select current_setting('effective_cache_size');
 current_setting 
-----------------
 4GB
(1 row)
设置参数并返回新值

testdb=# select set_config('effective_cache_size','2GB','false'); --最后一个参数is_local
                                                             设置为true表示只对当前事务生效。
 set_config 
------------
 2GB
(1 row)

服务器信号函数

服务器信号函数

向其他服务器进程发送控制信号,通常为超级用户使用

取消一个后端的当前查询,可以对另一个后端执行这个函数,这个后端有和调用这个函数的用户相同的
角色,在其他情况下,必须是超级用户
testdb=# select pg_cancel_backend(5491);
 pg_cancel_backend 
-------------------
 t
(1 row)

所有无服务器进程重新装置他们的配置文件
testdb=# select pg_reload_conf();
 pg_reload_conf 
----------------
 t
(1 row)

滚动服务器的日志文件
testdb=# select pg_rotate_logfile();
 pg_rotate_logfile 
-------------------
 t
(1 row)
未执行前,pg_log下的文件
[pg94@oracledb pg_log]$ ls
postgresql-2016-07-09_010729.csv  postgresql-2016-07-09_010751.csv
postgresql-2016-07-09_010729.log  postgresql-2016-07-09_010751.log
执行后pg_log下的文件
[pg94@oracledb pg_log]$ ls
postgresql-2016-07-09_010729.csv  postgresql-2016-07-09_010751.log
postgresql-2016-07-09_010729.log  postgresql-2016-07-09_010914.csv
postgresql-2016-07-09_010751.csv  postgresql-2016-07-09_010914.log

执行该语句,必须开启日志收集功能
logging_collector = on --是否开启日志收集开关,默认为off,变更之后必须重启数据库
log_destination = 'csvlog' --日志记录类型,默认是stderr只记录错误输出
log_directory = '/home/pg94/pgdata_test/pg_log' --日志存储路径,默认为$PGDATA/pg_log
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' --日志名称
log_connections = on --用户session登录时候是否写入日志,默认off
log_disconnections = on --用户session登出时是否写入日志,默认off
log_rotation_age = 1d   --保留单个文件的最大时长,默认为1d
log_rotation_size = 20MB --保留单个文件的最大尺寸,默认为10MB

终止一个后端。可以对另外一个后端执行该函数,必须具有相同的角色或者超级用户。
testdb=# select pg_terminate_backend(5854);
 pg_terminate_backend 
----------------------
 t
(1 row)

pid可以由pg_stat_activity表中的pid查询得到。

备份控制函数

为执行恢复创建一个命名点  --pg_lsn事务日志的位置
testdb=# select pg_create_restore_point('testrestore');
 pg_create_restore_point 
-------------------------
 0/A9BFA5D8
(1 row)
创建一个可以用作恢复目标的命名的事务日志记录,并返回相应的事务日志位置,给定的名字可以被
recovery_target_name使用以指定恢复将进行到的点。避免使用相同的名字创建多个恢复点,
因为恢复将在第一个名字匹配恢复目标的位置停止。


获取当前事务日志的插入位置
testdb=# select pg_current_xlog_insert_location();
 pg_current_xlog_insert_location 
---------------------------------
 0/AA8D5888
(1 row)
获取当前事务的写入位置
testdb=# select pg_current_xlog_location();
 pg_current_xlog_location 
--------------------------
 0/AA8D5960
(1 row)
插入点是事务日志在某个瞬间的“逻辑终点”,而实际的写入位置则是从服务器内部缓冲区写出时的终点,
写入位置是可以从服务器外部检测到的终点,即归档部分完成的事务日志文件,插入点主要用于服务器
调试目的。上面两个函数是只读操作,不需要超级用户权限

准备执行在线备份(超级用户或者复制的角色)
testdb=# select pg_start_backup('start_backup'); 
 pg_start_backup 
-----------------
 0/AB000060
(1 row)
pg_start_backup 向数据库集群的数据目录写入一个备份标签文件,执行一次检查点,返回备份的事务
日志起始位置。

第二个参数boolean类型,如果为true,指定尽可能快的执行pg_start_backup,强制立即一个检查点,
将导致I/O操作有一个尖峰,减缓任何当前执行的查询。

停止执行在线备份
testdb=# select pg_stop_backup();
NOTICE:  WAL archiving is not enabled; you must ensure that all required WAL
 segments are copied through other means to complete the backup
 pg_stop_backup 
----------------
 0/AB000160
(1 row)
pg_stop_backup 删除pg_start_backup创建的标签文件,并且在事务日志归档区里创建一个备份历史文件,
这个历史文件包含给予pg_start_backup的标签,备份的事务日志起始与终止位置,备份的起始时间和终止时间,
返回值是备份的事务日志终止位置,计算出终止位置后,当前事务日志的插入点将自动前进到下一个事务日志文件,
这样结束的事务日志文件可以被立即归档从而完成备份。

如果在线专属备份还在进行中则为真
testdb=# select pg_is_in_backup();
 pg_is_in_backup 
-----------------
 f
(1 row)

在线备份开始时间
testdb=# select pg_backup_start_time();
  pg_backup_start_time  
------------------------
 2016-07-09 19:53:34+08
(1 row)


强制转向一个新的事物日志文件
testdb=# select pg_switch_xlog();
 pg_switch_xlog 
----------------
 0/AC000158
(1 row)
移动到下一个事务日志文件,允许当前日志文件归档,返回值是刚刚完成的事务日志文件的事务日志结束位置+1,
如果自从最后一次事务日志切换以来没有活动的事务日志,那么该函数什么也不做,直接返回当前使用的事务日
志文件的开始位置。


允许前pg_xlog文件
[pg94@oracledb pg_xlog]$ ls
0000000100000000000000AB  0000000100000000000000AE  0000000100000000000000B1
0000000100000000000000AC  0000000100000000000000AF  0000000100000000000000B2
0000000100000000000000AD  0000000100000000000000B0  archive_status
运行后
[pg94@oracledb pg_xlog]$ ls
0000000100000000000000AC  0000000100000000000000AF  0000000100000000000000B2
0000000100000000000000AD  0000000100000000000000B0  0000000100000000000000B3
0000000100000000000000AE  0000000100000000000000B1  archive_status

将事务日志的位置字符串转换为文件名
testdb=# select pg_xlogfile_name('0/B032BA68');
     pg_xlogfile_name     
--------------------------
 0000000100000000000000B0
(1 row)
抽取事务日志文件名称,如果给定的事务日志位置恰好位于事务日志文件的交界上,返回前一个事务日志文件的名字。
这对于管理事务日志归档来说是期望的行为,因为前一个文件是最后一个需要归档的文件。

将事务日志的位置字符串转换为文件名并返回在文件中的字节偏移量
testdb=# select pg_xlogfile_name_offset('0/B032BA68');
      pg_xlogfile_name_offset       
------------------------------------
 (0000000100000000000000B0,3324520)
(1 row)

两个事务日志位置之间的区别
testdb=# select  pg_xlog_location_diff('0/B1000038','0/B1000028');
 pg_xlog_location_diff 
-----------------------
                    16
(1 row)
计算两个事务日志位置之间在字节上的不同。

恢复控制函数

如果恢复任然在进行中则返回true
testdb=# select pg_is_in_recovery();
 pg_is_in_recovery 
-------------------
 f
(1 row)

在备库上执行
获取最后一个事务日志接收并通过流媒体复制同步到磁盘的日志位置。如果流复制仍在进行,
这个数值将增加,如果恢复完成那么这个值将保持在恢复期间最后接手和同步到磁盘的WAL记录值。
如果不用流复制,或者还没开始,那么这个函数返回NULL
postgres=# select pg_last_xlog_receive_location();
 pg_last_xlog_receive_location 
-------------------------------
 2/8A000100
(1 row)

获取最后一个事物日志在恢复时重放的位置,如果恢复仍在进行,这将增加,如果恢复已经完成,
将保持静止在恢复期间最后应用的WAL记录值。
当服务以及没有恢复的正常启动时,返回NULL。
postgres=# select pg_last_xlog_replay_location();
 pg_last_xlog_replay_location 
------------------------------
 2/8A000388
(1 row)

获取最后一个事务在恢复时的时间戳,这是为在主节点上生成的事务提交或终止WAL记录的时间。
如果没有事务在恢复重放,则返回NULL,
如果恢复仍然在进行,则将增加,如果恢复已经完成,那么将保持在最后应用的值。

pg_last_xact_replay_timestamp()


恢复控制函数

如果恢复暂停则返回true
testdb=# select pg_is_xlog_replay_paused();
 pg_is_xlog_replay_paused 
--------------------------
 f
(1 row)

立即暂停恢复
testdb=# select pg_xlog_replay_pause();
 pg_xlog_replay_pause 
----------------------
 
(1 row)

testdb=# select pg_is_xlog_replay_paused();
 pg_is_xlog_replay_paused 
--------------------------
 t
(1 row)

如果恢复暂停了,那么重新启动
testdb=# select pg_xlog_replay_resume();
 pg_xlog_replay_resume 
-----------------------
 
(1 row)

testdb=# select pg_is_xlog_replay_paused();
 pg_is_xlog_replay_paused 
--------------------------
 f
(1 row)


当恢复暂停时,没有进一步的数据库更改,如果是在热备里,所有新的查询将看到相同一致的数据库快照,并且不会有进一步的查询冲突产生,直到恢复继续。

如果不能使用流复制,那么暂停状态将没有问题的无限延续。当流复制可用时,将连续接受WAL日志,将最终填满可用磁盘空间,取决于暂停的持续时间,wal的生产速度和磁盘的可用空间。
 

保存当前的快照并返回标识符

testdb=#begin transaction isolation level repeatable read ;
BEGIN

testdb=#  select pg_export_snapshot();
 pg_export_snapshot
--------------------
 00000C8A-1
(1 row)

在$PGDATA/pg_snapshot下生成一个

[pg94@oracledb pg_snapshots]$ ls
00000C8A-1

继续执行该函数,生成第二个

[pg94@oracledb pg_snapshots]$ ls
00000C8A-1  00000C8A-2

testdb=# end;
COMMIT

之后,该文件被删除。


复制函数

max_replication_slot必须大于0
testdb=# select pg_create_physical_replication_slot('test_physlot');
 pg_create_physical_replication_slot 
-------------------------------------
 (test_physlot,)
(1 row)
创建一个物理复制槽,从物理槽流动更改仅有流复制槽协议的时候是可能的。
在备库的recovery.conf中设置primary_slotname = 'test_physlot'

删除物理槽
testdb=# select pg_drop_replication_slot('test_physlot');
 pg_drop_replication_slot 
--------------------------
 
(1 row)

需要在备库的recovery.conf中删除primary_slotname = 'test_physlot',然后重启备库。

创建逻辑复制槽
testdb=# select pg_create_logical_replication_slot('test2','test_decoding');
 pg_create_logical_replication_slot 
------------------------------------
 (test2,2/B29A2178)
(1 row)
需要设置postgresql.conf文件中的
wal_level=logical
max_replication_slots=2  --至少等于1

testdb=#  select * from pg_replication_slots where slot_name='test2';
 slot_name |    plugin     | slot_type | datoid | database | active | xmin | catalog_xmin | res
tart_lsn 
-----------+---------------+-----------+--------+----------+--------+------+--------------+----
---------
 test2     | test_decoding | logical   |  16385 | testdb   | f      |      |         3234 | 2/B
29B6470
(1 row)


返回逻辑槽中的变化
pg_logical_slot_get_changes(slot_name name, upto_lsn pg_lsn, upto_nchanges int, VARIADIC options text[]) 

testdb=# create table test3(id int);
CREATE TABLE
testdb=# select * from pg_logical_slot_get_changes('test2',NULL,NULL);
  location  | xid  |    data     
------------+------+-------------
 2/B29A2390 | 3233 | BEGIN 3233
 2/B29B6440 | 3233 | COMMIT 3233
(2 rows)

testdb=# insert into test3 values (1);
INSERT 0 1
testdb=# select * from pg_logical_slot_get_changes('test2',NULL,NULL);
  location  | xid  |                   data                    
------------+------+-------------------------------------------
 2/B29B64B0 | 3234 | BEGIN 3234
 2/B29B64B0 | 3234 | table public.test3: INSERT: id[integer]:1
 2/B29B6530 | 3234 | COMMIT 3234
(3 rows)
upto_lsn非空,那么解码将只包括在该lsn之前提交的事务,upto_nchanges 非空,解码的行数将在超过指定的值时停止。
两个都为空的时候,解码将从最后一次访问的点开始,逻辑解码到wal的结束。
该函数只能查一次。下一次查询将为空。

pg_logical_slot_peek_changes(slot_name name, upto_lsn pg_lsn, upto_nchanges int, VARIADIC options text[]) 

和上面函数一样,可以重复查询,没有消耗修改。

作为bytea返回,功能与上面的函数一样
testdb=# insert into test3 values (1);
INSERT 0 1
testdb=# insert into test3 values (2);
INSERT 0 1
testdb=# select * from pg_logical_slot_get_binary_changes('test2',NULL,1);
  location  | xid  |                                         data                              
           
------------+------+---------------------------------------------------------------------------
-----------
 2/B29B6D50 | 3239 | \x424547494e2033323339
 2/B29B6D50 | 3239 | \x7461626c65207075626c69632e74657374333a20494e534552543a2069645b696e746567
65725d3a31
 2/B29B6EB8 | 3239 | \x434f4d4d49542033323339
(3 rows)


pg_logical_slot_peek_binary_changes(slot_name name, upto_lsn pg_lsn, upto_nchanges int, VARIADIC options text[]) 
与上面函数功能一样,能重复查询,不消耗修改。

 pg_recvlogical -h 192.168.30.7 -U reuser -d testdb --slot test --start -f - 
接收数据变化。

数据库对象管理函数

存储一个指定的数值需要的字节数
testdb=# select pg_column_size('\x434f4d4d49542033323339'::bytea);
 pg_column_size 
----------------
             15
(1 row)

指定OID代表的数据库使用的空间
testdb=# select pg_database_size(oid),oid,datname from pg_database where datname='testdb';
 pg_database_size |  oid  | datname 
------------------+-------+---------
        871681812 | 16385 | testdb

指定名称代表的数据库使用空间
testdb=# select pg_database_size(datname),oid,datname from pg_database where datname='testdb';
 pg_database_size |  oid  | datname 
------------------+-------+---------
        871681812 | 16385 | testdb
(1 row)

上面两个函数,执行的用户必须具有该数据库的connect权限。

附加到表的索引使用的总的磁盘空间
testdb=# select pg_indexes_size('tbl_idx'::regclass); 
 pg_indexes_size 
-----------------
        59064320
(1 row)

指定表或索引的指定分叉树('main','fsm','vm','init')使用的磁盘空间

testdb=# select pg_relation_size('tbl_idx'::regclass);  ‘main’的简写  关系的主数据支路的大小。
 pg_relation_size 
------------------
         76562432
(1 row)

testdb=# select pg_relation_size('tbl_idx'::regclass,'main');  
 pg_relation_size 
------------------
         76562432
(1 row)

testdb=# select pg_relation_size('tbl_idx'::regclass,'fsm'); 返回和这个关系有关的自由空间映射大小。
 pg_relation_size 
------------------
            40960
(1 row)

testdb=# select pg_relation_size('tbl_idx'::regclass,'vm'); 返回和这个关系有关的可见性映射的大小。
 pg_relation_size 
------------------
                0
(1 row)

testdb=# select pg_relation_size('tbl_idx'::regclass,'init'); 返回和这个关系有关的初始分支的大小。
 pg_relation_size 
------------------
                0
(1 row)


把用64位整数表示的字节计算的尺寸,转换成一个人类易读的尺寸。
testdb=# select pg_size_pretty(pg_relation_size('tbl_idx'::regclass,'main'));
 pg_size_pretty 
----------------
 73 MB
(1 row)

testdb=# select pg_size_pretty(23e10);
 pg_size_pretty 
----------------
 214 GB
(1 row)

指定表的大小,不包括索引,但是包括toast,自由空间映射和可见性映射。
testdb=# select pg_table_size('tbl_idx');
 pg_table_size 
---------------
      76611584
(1 row)

表空间使用的磁盘空间
postgres=# select pg_size_pretty(pg_tablespace_size('tblspace'));
 pg_size_pretty 
----------------
 201 MB
(1 row)

postgres=# select pg_size_pretty(pg_tablespace_size(50453));
 pg_size_pretty 
----------------
 201 MB
(1 row)

上面两个函数,执行的用户必须对该表空间具有create权限。

表的使用总的磁盘空间,包括toast,索引,相当于pg_table_size + pg_indexes_size
testdb=# select pg_size_pretty(pg_total_relation_size('tbl_idx'::regclass));
 pg_size_pretty 
----------------
 129 MB
(1 row)

数据库对象位置函数

指定关系的文件节点,可以是表,序列,索引,压缩包的OID或者名字,对于系统目录,返回0,不存在则返回NULL。
testdb=# select pg_relation_filenode('tbl_idx'::regclass); pg_relation_filenode 
----------------------
                50445
(1 row)

指定关系的文件路径名
testdb=# select pg_relation_filepath('tbl_idx'::regclass); 
             pg_relation_filepath             
----------------------------------------------
 pg_tblspc/50453/PG_9.4_201409291/16385/50445
(1 row)

找出一个表空间和节点相关的关系
testdb=# select pg_filenode_relation(50453,50445);
 pg_filenode_relation 
----------------------
 tbl_idx
(1 row)

通用文件访问函数

列出目录中的文件,除'.'和'..'
testdb=# select pg_ls_dir('.');
      pg_ls_dir       
----------------------
 pg_logical
 PG_VERSION
 pg_twophase
 pg_subtrans
 postmaster.pid
 pg_stat
 pg_ident.conf
 pg_xlog
 pg_snapshots
 pg_dynshmem
 pg_hba.conf
 postgresql.auto.conf
 pg_notify
 pg_clog
 pg_replslot
 global
 pg_tblspc
 postgresql.conf
 base
 postmaster.opts
 pg_serial
 pg_multixact
 pg_stat_tmp
(23 rows)

只能是pgdata目录,或者子目录

返回一个文件文件的内容,从offset开始,返回length字节,如果offset是负数就是相对于文件结尾回退的数目。
两个参数都省略,则返回全部文件内容,从文件读取到的字节,在服务器编码里被解释为一个字符串。如果编码不可用则抛出错误。
testdb=# select pg_read_file('./pg_ident.conf',1,26);
        pg_read_file        
----------------------------
  PostgreSQL User Name Maps
(1 row)
offset 偏移量,
length 长度

以二进制文件的形式输出文件的内容,不执行编码检查,与convert_from函数连用,可以用来读取指定编码的文件。
testdb=# select pg_read_binary_file('./pg_ident.conf',1,10);
  pg_read_binary_file   
------------------------
 \x20506f73746772655351
(1 row)

testdb=# SELECT convert_from(pg_read_binary_file('./pg_ident.conf',1,11), 'UTF8');
 convert_from 
--------------
  PostgreSQL
(1 row)


返回一个文件的信息
testdb=# select pg_stat_file('./pg_ident.conf');
                                     pg_stat_file                                     
--------------------------------------------------------------------------------------
 (1636,"2016-07-18 10:34:43+08","2016-06-25 13:20:41+08","2016-06-25 13:20:41+08",,f)
(1 row)

分别表示文件大小,最后的访问的时间戳,最后修改的时间戳,最后文件状态改变的时间戳,WINDOWS下文件创建的时间戳,是否是一个路径。

获取修改时间
testdb=# select (pg_stat_file('./pg_ident.conf')).modification;;
      modification      
------------------------
 2016-06-25 13:20:41+08
(1 row)

咨询锁函数

获取排他会话级别咨询锁
pg_advisory_lock(key bigint) 

session A
testdb=# select pg_advisory_lock(1);
 pg_advisory_lock 
------------------
 
(1 row)

相应的解锁函数为testdb=# select pg_advisory_unlock(1);
 
启动一个session B,当前数据库下就不能获取排他会话咨询锁了。
testdb=# select pg_try_advisory_lock(1);
 pg_try_advisory_lock 
----------------------
 f
(1 row)
只有当session A释放该锁才能加咨询排他锁,当SESSION A加锁几次,则要解锁几次,
也可以使用 pg_advisory_unlock_all() 释放所有当前会话基本咨询锁。

pg_advisory_lock(key1 int, key2 int)
pg_advisory_unlock(key1 int, key2 int) 
与上面咨询锁一样使用,只是用的是两个32位不重叠键标识,上面使用64位键值标识。



会话级别共享咨询锁
SESSION A
testdb=# select pg_advisory_lock_shared(1);
 pg_advisory_lock_shared 
-------------------------
 
(1 row)

postgres=# select * from pg_locks ;
  locktype  | database | relation | page | tuple | virtualxid | transactionid | classid | objid
 | objsubid | virtualtransaction | pid  |      mode       | granted | fastpath 
------------+----------+----------+------+-------+------------+---------------+---------+------
-+----------+--------------------+------+-----------------+---------+----------
 relation   |    13003 |    11187 |      |       |            |               |         |      
 |          | 4/1007             | 4429 | AccessShareLock | t       | t
 virtualxid |          |          |      |       | 4/1007     |               |         |      
 |          | 4/1007             | 4429 | ExclusiveLock   | t       | t
 advisory   |    16385 |          |      |       |            |               |       0 |     1
 |        1 | 3/0                | 3999 | ShareLock       | t       | f
(3 rows)

第三条记录为加的共享咨询锁

SESSION B
testdb=# select pg_try_advisory_lock_shared(1);
 pg_try_advisory_lock_shared 
-----------------------------
 t
(1 row)


testdb=# select * from pg_locks ;
  locktype  | database | relation | page | tuple | virtualxid | transactionid | classid | objid
 | objsubid | virtualtransaction | pid  |      mode       | granted | fastpath 
------------+----------+----------+------+-------+------------+---------------+---------+------
-+----------+--------------------+------+-----------------+---------+----------
 relation   |    16385 |    11187 |      |       |            |               |         |      
 |          | 6/240              | 4525 | AccessShareLock | t       | t
 virtualxid |          |          |      |       | 6/240      |               |         |      
 |          | 6/240              | 4525 | ExclusiveLock   | t       | t
 advisory   |    16385 |          |      |       |            |               |       0 |     1
 |        1 | 5/0                | 4366 | ShareLock       | t       | f
 advisory   |    16385 |          |      |       |            |               |       0 |     1
 |        1 | 3/0                | 3999 | ShareLock       | t       | f
(4 rows)

第四条记录为session B 加的共享咨询锁。

释放共享咨询所
SESSION A
testdb=# select pg_advisory_unlock_shared(1);
 pg_advisory_unlock_shared 
---------------------------
 t
(1 row)

testdb=# select * from pg_locks ;
  locktype  | database | relation | page | tuple | virtualxid | transactionid | classid | objid
 | objsubid | virtualtransaction | pid  |      mode       | granted | fastpath 
------------+----------+----------+------+-------+------------+---------------+---------+------
-+----------+--------------------+------+-----------------+---------+----------
 relation   |    16385 |    11187 |      |       |            |               |         |      
 |          | 6/241              | 4525 | AccessShareLock | t       | t
 virtualxid |          |          |      |       | 6/241      |               |         |      
 |          | 6/241              | 4525 | ExclusiveLock   | t       | t
 advisory   |    16385 |          |      |       |            |               |       0 |     1
 |        1 | 5/0                | 4366 | ShareLock       | t       | f
(3 rows)

释放了一个共享咨询锁。

也可以使用
testdb=# select pg_advisory_unlock_all() ;
 pg_advisory_unlock_all 
------------------------
 
(1 row)
释放当前会话基本的所有咨询锁。


pg_advisory_lock_shared(key1 int, key2 int)
pg_advisory_unlock_shared(key1 int, key2 int) 
与上面类似

pg_try_advisory_lock(key bigint)  boolean 尝试获取排他会话级别咨询锁 
pg_try_advisory_lock(key1 int, key2 int)  boolean 尝试获取排他会话级别咨询锁 
pg_try_advisory_lock_shared(key bigint)  boolean 尝试获取共享会话级别咨询锁 
pg_try_advisory_lock_shared(key1 int, key2 int)  boolean 尝试获取共享会话级别咨询锁

senssion级别的锁需要手动释放,或者session结束后释放。

begin,end之间,获取一个advisory_lock时,事务被回滚,锁不会被回滚。
testdb=# begin;
BEGIN
testdb=# select pg_advisory_lock(1);
 pg_advisory_lock 
------------------
 
(1 row)

testdb=# select * from pg_locks ;
  locktype  | database | relation | page | tuple | virtualxid | transactionid | classid | objid
 | objsubid | virtualtransaction | pid  |      mode       | granted | fastpath 
------------+----------+----------+------+-------+------------+---------------+---------+------
-+----------+--------------------+------+-----------------+---------+----------
 relation   |    16385 |    11187 |      |       |            |               |         |      
 |          | 6/243              | 4525 | AccessShareLock | t       | t
 virtualxid |          |          |      |       | 6/243      |               |         |      
 |          | 6/243              | 4525 | ExclusiveLock   | t       | t
 virtualxid |          |          |      |       | 3/216      |               |         |      
 |          | 3/216              | 3999 | ExclusiveLock   | t       | t
 advisory   |    16385 |          |      |       |            |               |       0 |     1
 |        1 | 3/216              | 3999 | ExclusiveLock   | t       | f
(4 rows)

testdb=# rollback ;
ROLLBACK

testdb=# select * from pg_locks ;
  locktype  | database | relation | page | tuple | virtualxid | transactionid | classid | objid
 | objsubid | virtualtransaction | pid  |      mode       | granted | fastpath 
------------+----------+----------+------+-------+------------+---------------+---------+------
-+----------+--------------------+------+-----------------+---------+----------
 relation   |    16385 |    11187 |      |       |            |               |         |      
 |          | 6/244              | 4525 | AccessShareLock | t       | t
 virtualxid |          |          |      |       | 6/244      |               |         |      
 |          | 6/244              | 4525 | ExclusiveLock   | t       | t
 advisory   |    16385 |          |      |       |            |               |       0 |     1
 |        1 | 3/0                | 3999 | ExclusiveLock   | t       | f
(3 rows)

我们可以看到advisor_lock()没被回滚掉。
 advisory_lock_shared()也不会被回滚掉。


在事务开始前,获取一个pg_advisory_lock(1),然后在begin后释放改锁,就算回滚,也还是被释放。不会恢复。

testdb=# select pg_advisory_lock(1);
 pg_advisory_lock 
------------------
 
(1 row)

testdb=# select * from pg_locks where objid=1;
 locktype | database | relation | page | tuple | virtualxid | transactionid | classid | objid |
 objsubid | virtualtransaction | pid  |     mode      | granted | fastpath 
----------+----------+----------+------+-------+------------+---------------+---------+-------+
----------+--------------------+------+---------------+---------+----------
 advisory |    16385 |          |      |       |            |               |       0 |     1 |
        1 | 3/0                | 3999 | ExclusiveLock | t       | f
(1 row)

testdb=# begin;
BEGIN
testdb=# select pg_advisory_unlock(1);
 pg_advisory_unlock 
--------------------
 t
(1 row)

testdb=# select * from pg_locks where objid=1;
 locktype | database | relation | page | tuple | virtualxid | transactionid | classid | objid |
 objsubid | virtualtransaction | pid | mode | granted | fastpath 
----------+----------+----------+------+-------+------------+---------------+---------+-------+
----------+--------------------+-----+------+---------+----------
(0 rows)

testdb=# rollback ;
ROLLBACK

testdb=# select * from pg_locks where objid=1;
 locktype | database | relation | page | tuple | virtualxid | transactionid | classid | objid |
 objsubid | virtualtransaction | pid | mode | granted | fastpath 
----------+----------+----------+------+-------+------------+---------------+---------+-------+
----------+--------------------+-----+------+---------+----------
(0 rows)


事务锁不可以显性释放,在事务结束的时候会自动释放(包含提交或回滚,正常或者不正常)。

开启一个事务,加事务咨询锁。
testdb=# begin;
BEGIN
testdb=# select pg_advisory_xact_lock(1);
 pg_advisory_xact_lock 
-----------------------
 
(1 row)

testdb=# select * from pg_locks ;
  locktype  | database | relation | page | tuple | virtualxid | transactionid | classid | objid
 | objsubid | virtualtransaction | pid  |      mode       | granted | fastpath 
------------+----------+----------+------+-------+------------+---------------+---------+------
-+----------+--------------------+------+-----------------+---------+----------
 relation   |    16385 |    11187 |      |       |            |               |         |      
 |          | 5/44               | 2273 | AccessShareLock | t       | t
 virtualxid |          |          |      |       | 5/44       |               |         |      
 |          | 5/44               | 2273 | ExclusiveLock   | t       | t
 advisory   |    16385 |          |      |       |            |               |       0 |     1
 |        1 | 5/44               | 2273 | ExclusiveLock   | t       | f
(3 rows)

然后在加一个会话咨询锁
testdb=# select pg_advisory_lock(1);
 pg_advisory_lock 
------------------
 
(1 row)

testdb=# select * from pg_locks ;
  locktype  | database | relation | page | tuple | virtualxid | transactionid | classid | objid
 | objsubid | virtualtransaction | pid  |      mode       | granted | fastpath 
------------+----------+----------+------+-------+------------+---------------+---------+------
-+----------+--------------------+------+-----------------+---------+----------
 relation   |    16385 |    11187 |      |       |            |               |         |      
 |          | 5/44               | 2273 | AccessShareLock | t       | t
 virtualxid |          |          |      |       | 5/44       |               |         |      
 |          | 5/44               | 2273 | ExclusiveLock   | t       | t
 advisory   |    16385 |          |      |       |            |               |       0 |     1
 |        1 | 5/44               | 2273 | ExclusiveLock   | t       | f
(3 rows)

发现还是只有一个咨询锁,
testdb=# end;
COMMIT
testdb=# select * from pg_locks ;
  locktype  | database | relation | page | tuple | virtualxid | transactionid | classid | objid
 | objsubid | virtualtransaction | pid  |      mode       | granted | fastpath 
------------+----------+----------+------+-------+------------+---------------+---------+------
-+----------+--------------------+------+-----------------+---------+----------
 relation   |    16385 |    11187 |      |       |            |               |         |      
 |          | 5/45               | 2273 | AccessShareLock | t       | t
 virtualxid |          |          |      |       | 5/45       |               |         |      
 |          | 5/45               | 2273 | ExclusiveLock   | t       | t
 advisory   |    16385 |          |      |       |            |               |       0 |     1
 |        1 | 5/45               | 2273 | ExclusiveLock   | t       | f
(3 rows)
结束事务之后,还是有咨询锁,为会话咨询锁。

session,transaction级别的lock在同一个session中共用锁空间,所以在transaction中获取了锁,在同一个session中获取得到
但是在另外的session中就获取不到。


pg_advisory_lock锁定一个应用程序定义的资源,该资源可以用一个64位或两个不重叠的32位键值标识,如果已经有另外的会话锁定
了该资源,那么该函数将会阻塞到该资源可用为止,这是锁是排他的,多个锁定请求将会被压入栈中,因此,如果同一个资源被锁定了三次,
那么它必须被解锁三次以将资源释放给其他会话使用。

pg_advisory_lock_shared类似于pg_advisory_lock,不同之处仅在于共享锁可以和其他请求共享锁的会话共享,但排他锁除外。

pg_try_advisory_lock类似于pg_advisory_lock, 不同之处在于不会等待资源的释放,要么获取资源,加锁,返回true,要么返回false
表示目前不能锁定。

pg_try_advisory_lock_shared 类似于pg_try_advisory_lock,不同之处在于该函数获得的是一个共享锁。

pg_advisory_unlock 释放先前获取的排他会话级别咨询锁,如果释放成功则返回true,如果指定的锁并未持有,那么返回false,并且服务器
会返回一条SQL警告消息。(WARNING:  you don't own a lock of type ExclusiveLock)

pg_advisory_unlock_shared与pg_advisory_unlock类型,只是释放共享会话级别咨询锁。

pg_advisory_unlock_all将释放当前会话持有的所有会话级别锁,该函数在会话结束时隐含调用,即使客户端异常的断开连接也一样。

pg_advisory_xact_lock该所自动在当前事务的结束释放的,而且不能被显示的释放。

pg_advisory_xact_lock_shared与pg_advisory_lock_shared类似,在当前事务结束的时候释放,不能被显式的释放。

pg_try_advisory_xact_lock类似于pg_try_advisory_lock,如果获得该锁,自动在当前事务结束时释放,而不能被显式的释放。

pg_try_advisory_xact_lock_shared类似于pg_try_advisory_lock_shared如果获得该锁,自动在当前事务结束时释放,而不能被显式的释放。

 

转载于:https://my.oschina.net/vitofarm/blog/714477

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值