介绍
在本实验中,你将学习如何在 PostgreSQL 中设置事件触发器。事件触发器会捕获数据定义语言 (DDL) 事件,例如创建、修改或删除数据库对象。
你将创建一个专门的日志表和一个特殊函数来记录这些事件。然后,你将创建一个事件触发器,该触发器在 CREATE TABLE 命令之后触发,记录新表的详细信息。这个实践练习将指导你创建必要的组件,测试触发器的功能,并在之后清理数据库对象。
在本实验中,你将学习如何在 PostgreSQL 中设置事件触发器。事件触发器会捕获数据定义语言 (DDL) 事件,例如创建、修改或删除数据库对象。
你将创建一个专门的日志表和一个特殊函数来记录这些事件。然后,你将创建一个事件触发器,该触发器在 CREATE TABLE 命令之后触发,记录新表的详细信息。这个实践练习将指导你创建必要的组件,测试触发器的功能,并在之后清理数据库对象。
在此步骤中,你将创建记录 DDL 事件所需的数据库对象:一个用于存储日志的表和一个触发器将执行的函数。
首先,打开终端并使用 psql 交互式 shell 连接到 PostgreSQL 数据库。你将在该 shell 中执行后续的 SQL 操作。
sudo -u postgres psql
现在你应该会看到 PostgreSQL 提示符,它看起来像 postgres=#。
接下来,创建一个名为 event_log 的表来存储每个 DDL 事件的详细信息。该表将包含事件时间、类型、模式(schema)、对象名称以及已执行命令的列。
在 psql shell 中执行以下 SQL 命令:
CREATE TABLE event_log (
event_time timestamp with time zone,
event_type text,
schema_name text,
object_name text,
command_tag text
);
成功执行后,PostgreSQL 将响应:
CREATE TABLE
现在,创建将由 DDL 事件触发的函数。此函数 log_ddl_event 将向 event_log 表插入一条新记录。
CREATE OR REPLACE FUNCTION log_ddl_event()
RETURNS event_trigger
AS $$
BEGIN
INSERT INTO event_log (event_time, event_type, schema_name, object_name, command_tag)
SELECT now(), tg_event, ddl_command.schema_name, ddl_command.objid::regclass, tg_tag
FROM pg_event_trigger_ddl_commands() AS ddl_command;
END;
$$ LANGUAGE plpgsql;
让我们分解一下这个函数:
RETURNS event_trigger: 指定这是一个专门用于事件触发器的特殊类型的函数。AS $$ ... $$ LANGUAGE plpgsql: 使用 plpgsql 过程语言定义函数体。INSERT INTO event_log ...: 这是核心操作,它向我们的日志表插入一行新数据。now(): 一个标准函数,返回当前时间戳。tg_event, tg_tag: 在触发器函数内部可用的特殊变量,提供有关事件的上下文信息,例如 ddl_command_end 和 CREATE TABLE。pg_event_trigger_ddl_commands(): 一个返回描述已执行 DDL 命令的行集的函数。我们使用它来获取正在创建的对象的 schema_name 和 objid(对象标识符)。运行命令后,你将看到以下确认信息:
CREATE FUNCTION
你现在已成功设置了事件触发器的基础组件。
在日志表和函数就绪后,你现在可以创建事件触发器本身了。此触发器将监视特定的 DDL 命令,并在它们发生时执行你的日志记录函数。
在同一个 psql shell 中,执行以下命令来创建一个名为 log_table_creation 的事件触发器:
CREATE EVENT TRIGGER log_table_creation
ON ddl_command_end
WHEN TAG IN ('CREATE TABLE')
EXECUTE FUNCTION log_ddl_event();
让我们来分析一下这个语句的组成部分:
CREATE EVENT TRIGGER log_table_creation: 这为你的新事件触发器命名。ON ddl_command_end: 这指定了触发器的时间点。它将在 DDL 命令执行完成后触发。WHEN TAG IN ('CREATE TABLE'): 这是一个过滤条件。只有当命令标签匹配 CREATE TABLE 时,触发器才会激活。你也可以在这里添加其他标签,如 ALTER TABLE 或 DROP TABLE。EXECUTE FUNCTION log_ddl_event(): 这指定了当触发器的条件满足时要运行的函数。执行命令后,PostgreSQL 将确认其创建:
CREATE EVENT TRIGGER
你的事件触发器现在已激活,并将记录每一次新的表创建。
现在是时候测试事件触发器是否按预期工作了。你将创建一个新表,然后检查 event_log 表以查看创建事件是否已被记录。
首先,创建一个名为 employees 的简单表:
CREATE TABLE employees (
id serial PRIMARY KEY,
name text NOT NULL
);
CREATE TABLE 命令将正常执行,你将看到标准的确认信息:
CREATE TABLE
在后台,此操作应该已经触发了你的 log_table_creation 触发器。为了验证这一点,请查询 event_log 表以查看其内容:
SELECT schema_name, object_name, command_tag FROM event_log;
输出将显示多条记录。这是因为使用 serial PRIMARY KEY 创建表时,还会隐式创建序列 (sequence) 和主键约束 (primary key constraint)。事件触发器会捕获所有相关的 DDL 命令,从而在日志中产生多条条目。
schema_name | object_name | command_tag
-------------+------------------+--------------
public | employees_id_seq | CREATE TABLE
public | employees | CREATE TABLE
public | employees_pkey | CREATE TABLE
public | employees_id_seq | CREATE TABLE
(4 rows)
此结果证实了你的事件触发器正在正常运行,并记录了表创建及其依赖对象的事件。
移除不再需要的数据库对象是一种良好的实践。在最后一步,你将删除在此次实验中创建的事件触发器、表和函数。
首先,删除事件触发器:
DROP EVENT TRIGGER log_table_creation;
你将看到确认消息:
DROP EVENT TRIGGER
接下来,删除你创建的两个表 employees 和 event_log:
DROP TABLE employees;
DROP TABLE event_log;
PostgreSQL 将确认每个操作:
DROP TABLE
DROP TABLE
最后,删除触发器函数:
DROP FUNCTION log_ddl_event();
你将看到最终确认信息:
DROP FUNCTION
你现在已成功清理了在此次实验中创建的所有对象。要退出 psql shell 并返回到常规终端提示符,请输入 \q 并按 Enter 键。
\q
在此次实验中,你学习了如何在 PostgreSQL 中实现事件触发器来监控 DDL 活动。你创建了一个日志表来存储事件数据,并创建了一个 PL/pgSQL 函数来填充它。然后,你定义了一个事件触发器,该触发器专门捕获 CREATE TABLE 事件,并将其与你的日志函数关联起来。通过测试触发器并验证日志条目,你获得了关于这些组件如何协同工作的实践经验。最后,你通过清理创建的触发器、表和函数,练习了良好的数据库管理实践。