探索PostgreSQL模式(schema)的奥秘

发表时间: 2021-03-01 22:04

模式(schema)可以连接为一个命名空间或目录。不同的模式下可以有相同的名称的表、函数等对象且互相不冲突。模式是为了便于管理,只要有权限,每个模式的对象可以互相调用.

在PostgreSQL中,一个数据库包含一个或多个模式,模式又包含了表、函数及操作符等数据库对象。在PostgreSQL中,不能同时访问不同数据库中的对象,当要访问另一个数据库中的表或其他对象时,需要重新连接到这个新的数据库,而模式没有此限制。

我们需要使用模式的主要原因:

  • 允许多个用户在使用同一个数据库时彼此互不干扰
  • 把数据库对象放在不同的模式下,然后组织成逻辑组,让它们便于管理
  • 第三方的应用可以放在不同的模式下,这样就不会和其他对象的名字冲突了。

6.1模式使用

 CREATE SCHEMA schema_name [ AUTHORIZATION role_specification ] [ schema_element [ ... ] ] CREATE SCHEMA AUTHORIZATION role_specification [ schema_element [ ... ] ] CREATE SCHEMA IF NOT EXISTS schema_name [ AUTHORIZATION role_specification ] CREATE SCHEMA IF NOT EXISTS AUTHORIZATION role_specification  where role_specification can be:      user_name   | CURRENT_USER   | SESSION_USER

模式使用例子:

 1.创建schema salesapp [root@node1 ~]# su - postgres -bash-4.2$ psql postgres=# \c testdb; postgres=# CREATE ROLE salesapp with LOGIN ENCRYPTED PASSWORD 'abc123'; testdb=# \du                                    List of roles  Role name |                         Attributes                         | Member of -----------+------------------------------------------------------------+-----------  postgres  | Superuser, Create role, Create DB, Replication, Bypass RLS | {}  salesapp  |                                                            | {}  testdb=# CREATE SCHEMA AUTHORIZATION salesapp; CREATE SCHEMA  这里可以直接 testdb=# CREATE SCHEMA salesapp; 或者 testdb=# CREATE SCHEMA salesapp AUTHORIZATION salesapp;  testdb=# \dn    List of schemas    Name   |  Owner ----------+----------  public   | postgres  salesapp | salesapp (2 rows)  testdb=# create table salesapp.t1(c1 int); CREATE TABLE  testdb=# select * from pg_tables where schemaname='salesapp';  schemaname | tablename | tableowner | tablespace | hasindexes | hasrules | hastriggers | rowsecurity ------------+-----------+------------+------------+------------+----------+-------------+-------------  salesapp   | t1        | postgres   |            | f          | f        | f           | f (1 row)  testdb=# insert into salesapp.t1 values(1); INSERT 0 1 testdb=# insert into salesapp.t1 values(2); INSERT 0 1 testdb=# select * from salesapp.t1;  c1 ----   1   2 (2 rows)  ===================================================================== 2.用salesapp用户连接数据库,可以看到这个schema下面的表 -bash-4.2$ psql -h 127.0.0.1 -p 5432 testdb salesapp Password for user salesapp: psql (13.2Type "help" for help.  testdb=> \dt          List of relations   Schema  | Name | Type  |  Owner ----------+------+-------+----------  public   | e    | table | postgres  public   | t    | table | postgres  public   | t2   | table | postgres  public   | x1   | table | postgres  public   | x2   | table | postgres  public   | x3   | table | postgres  salesapp | t1   | table | postgres  salesapp | t11  | table | postgres ===================================================================== 3.删除schema testdb=# DROP SCHEMA salesappold; ERROR:  cannot drop schema salesappold because other objects depend on it DETAIL:  table salesappold.t1 depends on schema salesappold table salesappold.t11 depends on schema salesappold HINT:  Use DROP ... CASCADE to drop the dependent objects too. testdb=# \dn     List of schemas     Name     |  Owner -------------+----------  public      | postgres  salesappold | sales (2 rows)  testdb=# DROP SCHEMA salesappold CASCADE; NOTICE:  drop cascades to 2 other objects DETAIL:  drop cascades to table salesappold.t1 drop cascades to table salesappold.t11 DROP SCHEMA testdb=# \dn   List of schemas   Name  |  Owner --------+----------  public | postgres (1 row)

在模式中修改名称和属主

ALTER SCHEMA name RENAME TO newname

ALTER SCHEMA name OWNER TO newowner

 1. 改模式名称 postgres=# \c testdb; You are now connected to database "testdb" as user "postgres". testdb=# \dn    List of schemas    Name   |  Owner ----------+----------  public   | postgres  salesapp | salesapp (2 rows)  testdb=# alter schema salesapp rename to salesappold; ALTER SCHEMA testdb=# \dn     List of schemas     Name     |  Owner -------------+----------  public      | postgres  salesappold | salesapp (2 rows)  2. 改模式属主 testdb=# CREATE ROLE sales with LOGIN ENCRYPTED PASSWORD 'abc123'; CREATE ROLE testdb=# alter schema salesappold owner to sales; ALTER SCHEMA testdb=# \dn     List of schemas     Name     |  Owner -------------+----------  public      | postgres  salesappold | sales (2 rows)  注意:要指定OWNER的话,请确保OWNER已存在。

6.2公共模式

创建或者访问模式中的对象,需要先写出一个受修饰的名字,这个名字包含模式名及表名,用"点"分开。

schema_name.table_name

通常情况下,创建和访问表的时候不用指定模式,实际上这时访问的是"public"模式。每当我们创建了一个新的数据库时,PostgreSQL会自动创建一个名为"public"的模式,当登陆该数据库时,如果没有特殊指定,都是以该模式(public)操作各种数据对象的。

6.3模式的搜索路径

使用一个数据库对象时,虽然可以使用它的全称来定位对象,但这样一来,每次都不得不输入schema_name.object_name,这显然很繁琐。PostgreSQL提供了模式搜索路径,指定在哪个模式下执行,类似于设置默认模式。

 1.查看当前SCHEMA,并列出public模式下的表 postgres=# \c testdb You are now connected to database "testdb" as user "postgres". testdb=# SHOW search_path;    search_path -----------------  "$user", public (1 row)  testdb=# \d         List of relations  Schema | Name | Type  |  Owner --------+------+-------+----------  public | e    | table | postgres  public | t    | table | postgres  public | t1   | table | postgres  public | t2   | table | postgres  public | x1   | table | postgres  public | x2   | table | postgres  public | x3   | table | postgres  testdb=# create schema sales; CREATE SCHEMA testdb=# SET search_path TO sales,public; 或者 testdb=# SET search_path TO sales;  testdb=# SHOW search_path;   search_path ---------------  sales, public (1 row)  testdb=# create table sales.t1(c1 int); CREATE TABLE testdb=# \d         List of relations  Schema | Name | Type  |  Owner --------+------+-------+----------  public | e    | table | postgres  public | t    | table | postgres  public | t2   | table | postgres  public | x1   | table | postgres  public | x2   | table | postgres  public | x3   | table | postgres  sales  | t1   | table | postgres (7 rows)  testdb=# create table t2(c1 int); CREATE TABLE testdb=# \d         List of relations  Schema | Name | Type  |  Owner --------+------+-------+----------  public | e    | table | postgres  public | t    | table | postgres  public | x1   | table | postgres  public | x2   | table | postgres  public | x3   | table | postgres  sales  | t1   | table | postgres  sales  | t2   | table | postgres (7 rows)  可以看到,我们不指定schema建表,也会默认在sales下面。 

6.4模式权限

默认情况下,用户无法访问模式不属于他们的对象。若要访问,模式的所有者必须在模式上赋予他们"USAGE"权限。为了让用户使用模式中的对象,可能需要赋予适合该对象的额外权限。

用户也可以在别人的模式里创建对象,当然,这需要被赋予了该模式上的"CREATE"权限。请注意,默认情况下每个人在public模式上都有"CREATE"和"USAGE"权限,也就是允许所有可以连接到指定数据库上的用户在这里创建对象。如果你不打算这么做,可以撤销这个权限

 testdb=# REVOKE CREATE ON SCHEMA PUBLIC FROM PUBLIC; 第一个PUBLIC是模式名称 第二个PUBLIC是所有用户  用sales用户连接testdb -bash-4.2$ psql -h 127.0.0.1 -p 5432 testdb sales; Password for user sales: xxx psql (13.2) Type "help" for help.  testdb=> create table t3(c1 int); ERROR:  permission denied for schema public LINE 1: create table t3(c1 int); 这里可以看到提示没有public模式权限。