2

我的任务是制作一个触发器,它会在我们的程序员在数据库中创建、更改、替换或删除触发器时触发。它必须将他们的更改记录到我所做的类似于SYS.trigger$表的 2 个数据表中,并添加一些关于对它们进行更改的用户的额外信息。我从名为GalaktikaGalaxy的 ERP 系统中现有的审计功能中复制了日志记录的原则,以使其变得简单。但是,我遇到了一个众所周知的问题ORA-04089: no one can create triggers on system tables并坚持了下来。

现在我正在寻找一种根据数据库规则轻轻修改触发器的方法。这是原始代码:

CREATE OR REPLACE TRIGGER MRK_AlTrigger$
   BEFORE DELETE OR INSERT OR UPDATE
   ON SYS.TRIGGER$
   REFERENCING NEW AS New OLD AS Old
   FOR EACH ROW
DECLARE
   Log_Rec   MRK_TRIGGERS_LOG_HEADER.NREC%TYPE;
BEGIN
   INSERT INTO MRK_TRIGGERS_LOG_HEADER (DATEOFCHANGE,
                                            USERCODE,
                                            OPERATION,
                                            OBJ#)
    VALUES (
              SYSDATE,
              UID,
              CASE
                 WHEN INSERTING THEN 0
                 WHEN UPDATING THEN 1
                 WHEN DELETING THEN 2
              END,
              CASE
                 WHEN INSERTING OR UPDATING THEN :new.OBJ#
                 ELSE :old.OBJ#
              END)
     RETURNING NRec
          INTO Log_Rec;

   IF INSERTING OR UPDATING
   THEN
      INSERT INTO MRK_TRIGGERS_LOG_SPECIF (LOGLINK,
                                               OBJ#,
                                               TYPE#,
                                               UPDATE$,
                                               INSERT$,
                                               DELETE$,
                                               BASEOBJECT,
                                               REFOLDNAME,
                                               REFNEWNAME,
                                               DEFINITION,
                                               WHENCLAUSE,
                                               ACTION#,
                                               ACTIONSIZE,
                                               ENABLED,
                                               PROPERTY,
                                               SYS_EVTS,
                                               NTTRIGCOL,
                                               NTTRIGATT,
                                               REFPRTNAME,
                                               ACTIONLINENO)
       VALUES (Log_Rec,
               :new.OBJ#,
               :new.TYPE#,
               :new.UPDATE$,
               :new.INSERT$,
               :new.DELETE$,
               :new.BASEOBJECT,
               :new.REFOLDNAME,
               :new.REFNEWNAME,
               :new.DEFINITION,
               :new.WHENCLAUSE,
               :new.ACTION#,
               :new.ACTIONSIZE,
               :new.ENABLED,
               :new.PROPERTY,
               :new.SYS_EVTS,
               :new.NTTRIGCOL,
               :new.NTTRIGATT,
               :new.REFPRTNAME,
               :new.ACTIONLINENO);
   END IF;
EXCEPTION
   WHEN OTHERS
   THEN
      -- Consider logging the error and then re-raise
      RAISE;
END MRK_AlTrigger$;
/

我也可以提供MRK_TRIGGERS_LOG_HEADERMRK_TRIGGERS_LOG_SPECIFDDL,但认为没有必要。所以总结一下,这里是我的问题:

  1. 如何将上述源代码修改为语法CREATE OR REPLACE TRIGGER ON DATABASE
  2. 我是在发明一个轮子吗?有没有常见的方法来做这些事情?(我注意到有些表有日志记录选项,但认为它是出于调试目的)

任何帮助将不胜感激!

UPD:我决定(感谢 APC)最好在源代码管理中保存不同版本的代码并在 DB 中仅记录修订号,但梦想自动执行此操作。

4

2 回答 2

1

“我们不希望吸引我们的程序员的整洁,所以我的老板要求必须有强大且自动的方式来记录更改。如果我们需要,还要快速恢复它们。”

换句话说,您需要对政治问题进行技术修复。这不起作用。但是,如果您有老板的支持,您可以解决问题。但它会变得混乱。

作为开发人员和开发 DBA,我一直站在这道防线的两边。我从痛苦的经历中知道,如果开发数据库——模式、配置参数、参考数据等——不受控制,那会有多糟糕。您的开发人员会觉得他们现在正在飞翔,但我向您保证,他们不会跟踪他们以脚本形式所做的所有更改。所以他们的改变是不可逆的或可重复的,当项目到达 UAT 时,部署很可能是一场惨败(给我买杯啤酒,我会告诉你一些故事)。

那么该怎么办?

特权访问

撤销开发人员对 SYSDBA 帐户和应用程序架构帐户的访问权限。除此之外,您可能会发现应用程序的某些部分开始依赖特权访问和/或硬编码密码,这些都是坏事;您不想在生产中包含这些违规行为。

由于您的开发人员已经习惯于拥有这种访问权限,因此这将非常不受欢迎。这就是为什么你需要老板的支持。您还必须采用替代方法,因此请将此操作留到最后。但请不要误会,这是结局。

源代码控制

数据库模式也是软件。它们是由程序构建的,就像应用程序的其余部分一样,只有源代码是 DDL 和 DML 脚本,而不是 C# 或 Java。这些脚本可以像任何其他源代码一样在 SVN 中进行控制。

如何在源代码管理中组织它?这可能很棘手。所以要认识到你有三类脚本:

  1. 部署对象的架构脚本
  2. 插入参考数据、管理系统参数等的配置脚本
  3. 构建以正确顺序调用其他脚本的脚本

管理模式脚本是最难做到的事情。我建议您为每个对象使用单独的脚本。此外,为表、索引和约束设置单独的脚本。这意味着您可以构建所有表,而无需按依赖顺序排列它们。

处理变更

诱惑将是只控制 CREATE TABLE 语句(或其他)。这是个错误。实际上,对模式的更改就像添加、删除或修改列一样可能会引入全新的对象。将 CREATE TABLE 语句存储为基线,然后将后续更改作为 ALTER TABLE 语句进行管理。

CREATE TABLE 和后续 ALTER TABLE 命令的一个文件,还是单独的文件?我很乐意拥有一个脚本:我不介意如果 CREATE TABLE 语句在我期望表已经存在时失败。但是,如果其他人将在生产中运行脚本,这可能会令人困惑。所以有一个基线脚本,然后单独的脚本来应用更改。每个时间框每个对象一个更改脚本是一个很好的折衷方案。

开发人员的更改包括

  • 更改表脚本以应用更改
  • 用于反转更改的镜像更改表脚本
  • 其他脚本,例如 DML
  • 更改参考号(他们将在 SVN 中使用)

因为你要在当天晚些时候介绍这个,所以你需要外交。因此,使更改过程轻松且易于使用。还要确保尽快检查并运行脚本。如果您反应迅速并且做事足够快,那么开发人员就不会因为访问受限而烦恼。

到达那里

首先你需要建立一个基线。像DBMS_METADATA这样的东西会给你所有当前对象的 CREATE 语句。您需要在 SVN 中组织它们并编写构建脚本。创建一个玩具数据库并做对。

这可能需要一些时间,因此请记住刷新 DDL 脚本,以便它们反映最新的语句。如果您现在可以使用非常方便的模式比较工具。

接下来,整理一下配置。希望您已经知道表格包含参考数据,否则请询问开发人员。

在您的玩具数据库练习中,对数据库进行切换并从头开始构建它。如果您喜欢冒险,您可以使用 Ant 或 Hudson 之类的工具来自动执行此操作,但至少您需要一些 shell 脚本来构建 SVN。

进行过渡

这是最大的。向开发商宣布新制度。让你的老板参加会议。提醒开发人员通知您他们对数据库所做的任何更改。

那晚:

  1. 使用 Data Pump 进行完整导出
  2. 删除所有应用程序架构。
  3. 从 SVN 构建应用程序
  4. 使用 Data Pump 重新加载数据 - 但不是数据结构
  5. 希望你不会有任何结构性问题;但是如果开发人员在没有告诉您的情况下进行了更改,您就会知道 - 他们不会在表中包含任何数据。
  6. 确保尽快撤销 SYSDBA 访问权限。

开发人员将需要访问一组模式,以便他们可以编写 ALTER 脚本。在开发人员没有本地个人数据库或私有模式来测试事物时,我建议您让他们访问该玩具数据库以测试更改脚本。或者,您可以让他们保留应用程序所有者的访问权限,因为您将定期重复 Trash'n'Rebuild 练习。一旦他们习惯了他们将失去任何他们没有告诉你的改变的想法,他们就会屈服并开始做正确的事情。

遗言

显然,这是很多模糊的空谈,缺乏扎实的细节。但这对你来说是政治。

后记

我昨天参加了一次 UKOUG 活动,并参加了 Regdate 的几个聪明人的会议。他们有一个产品Source Control for Oracle,它提供了(比如)SVN 和数据库之间的接口。它采用了与我上面概述的方法截然不同的方法。但他们的方法是合理的。他们的工具自动化了很多事情,我认为它在你目前的情况下可能会对你有很大帮助。我必须强调,我实际上并没有使用过这个产品,但我认为你应该检查一下 - 有 28 天的免费试用期。当然,如果你没有钱花,那么这对你没有帮助。

于 2013-07-17T14:13:51.360 回答
0

您可以在以下触发器属性中找到所需的信息

dictionary_obj_name 
dictionary_obj_owner
ora_sysevent

这是简单的 ON DATABASE 触发器

CREATE OR REPLACE TRIGGER trigger_name
AFTER CREATE OR DROP  ON DATABASE
BEGIN
  IF dictionary_obj_type = 'TRIGGER'
  THEN 

    INSERT INTO log_table ( trg_name, trg_owner, trg_action) VALUES (dictionary_obj_name,dictionary_obj_owner, ora_sysevent);

  END IF;
END;
/ 
于 2013-07-11T14:25:39.230 回答