利用Oracle DDL触发器实现DDL监控

前言

创建此触发器的主要目的是为了控制数据库的版本,虽然会将DDL语句保留但难免会出现遗漏,所以创建DDl触发器记录DDL操作,主要是用来核对数据库变更的SQL语句

创建用户并授权

#需要使用sys用户授权
CREATE USER DBADMIN IDENTIFIED BY DBADMIN;

GRANT CONNECT TO DBADMIN;
GRANT DBA TO DBADMIN;
GRANT SYS.V_$OPEN_CURSOR TO DBADMIN;

创建序列及表

DROP SEQUENCE SEQ_DDL_VERSION;
CREATE SEQUENCE SEQ_DDL_VERSION INCREMENT BY 1 START WITH 1 NOMAXVALUE NOMINVALUE NOCYCLE NOCACHE;

DROP TABLE TB_SYSTEM_DDL_LOGS CASCADE CONSTRAINTS;

/*==============================================================*/
/* TABLE: TB_SYSTEM_DDL_LOGS                                    */
/*==============================================================*/
CREATE TABLE TB_SYSTEM_DDL_LOGS
(
   EVENT_ID             VARCHAR2(32)         DEFAULT SYS_GUID() NOT NULL,
   EVENT_NAME           VARCHAR2(20),
   TERMINAL             VARCHAR2(50),
   DB_NAME              VARCHAR2(50),
   OBJECT_NAME          VARCHAR2(30),
   OBJECT_NAME_LIST     VARCHAR(300),
   OBJECT_OWNER         VARCHAR2(30),
   OBJECT_TYPE          VARCHAR2(20),
   IS_ALTER_COLUMN      VARCHAR(10),
   IS_DROP_COLUMN       VARCHAR(10),
   SQL_ID               VARCHAR(13),
   SQL_TEXT             CLOB,
   CURRENT_USER         VARCHAR(30),
   CURRENT_USERID       NUMBER,
   SESSION_USER         VARCHAR(10),
   SESSION_USERID       NUMBER,
   PROXY_USER           VARCHAR(30),
   PROXY_USERID         NUMBER,
   CURRENT_SCHEMA       VARCHAR(30),
   HOST                 VARCHAR(100),
   OS_USER              VARCHAR(60),
   IP_ADDRESS           VARCHAR(32),
   DDL_TIME             DATE                 DEFAULT SYSDATE,
   SESSION_ID           VARCHAR(32),
   VERSION_NO           NUMBER,
   CONSTRAINT PK_TB_SYSTEM_DDL_LOGS PRIMARY KEY (EVENT_ID)
);

COMMENT ON TABLE TB_SYSTEM_DDL_LOGS IS
‘【数据库日志】DDL日志表‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.EVENT_ID IS
‘事件ID自动生成‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.EVENT_NAME IS
‘事件名称‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.TERMINAL IS
‘客户端操作系统终端的名称‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.DB_NAME IS
‘数据库名称‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.OBJECT_NAME IS
‘DDL发生的对象名称‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.OBJECT_NAME_LIST IS
‘对象列表‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.OBJECT_OWNER IS
‘DDL发生对象的宿主‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.OBJECT_TYPE IS
‘对象类别‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.IS_ALTER_COLUMN IS
‘当列被修改的时候为真,否则为假 ‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.IS_DROP_COLUMN IS
‘当列被DROP的时候为真,否则为假 ‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.SQL_ID IS
‘SQL_ID‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.SQL_TEXT IS
‘SQL语句‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.CURRENT_USER IS
‘当前SESSION拥有权限的用户的名称(比如说当前SESSION是SYS,但是正在执行system.myproc,那么current_user就是system)‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.CURRENT_USERID IS
‘当前SESSION拥有的权限的用户的ID‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.SESSION_USER IS
‘session所属的用户名‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.SESSION_USERID IS
‘当前SESSION所属的用户id‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.PROXY_USER IS
‘打开当前SESSION的用户的名称‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.PROXY_USERID IS
‘打开当前SESSION的用户的ID‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.CURRENT_SCHEMA IS
‘当前SESSION缺省的SCHEMA名称,可以用SESSION SET CURRENT_SCHEMA语句修改‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.HOST IS
‘客户端的主机名称‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.OS_USER IS
‘客户端的操作系统用户名‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.IP_ADDRESS IS
‘客户端的IP地址‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.DDL_TIME IS
‘修改时间‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.SESSION_ID IS
‘SESSION_ID‘;

COMMENT ON COLUMN TB_SYSTEM_DDL_LOGS.VERSION_NO IS
‘版本号‘;

序列的作用主要是为了标识DDL操作版本,采用的是一种类似与SVN版本控制的方式,每发生一次变化版本号就加一

表是用来存储变更记录的

创建触发器

CREATE OR REPLACE TRIGGER TRIG_MONITOR_SYSTEM_DDL
AFTER DDL ON DATABASE
/**
 * 创建时间:2014年7月1日09:49:02
 * 描述:监控DDL操作并将DDL操作及DDL语句记录到日志表中
 */
DECLARE
      PRAGMA AUTONOMOUS_TRANSACTION;
      TR_EVENT_ID VARCHAR2(32);
      TR_TERMINAL VARCHAR2(50);
      TR_IPADDR VARCHAR2(30);
      TR_CUR_USER VARCHAR2(30);
      TR_CUR_USERID NUMBER;
      TR_SE_USER VARCHAR2(30);
      TR_SE_USERID NUMBER;
      TR_PROXY_USER VARCHAR2(30);
      TR_PROXY_USERID NUMBER;
      TR_CUR_SC VARCHAR2(30);
      TR_HOST VARCHAR2(100);
      TR_OS_USER VARCHAR2(60);
      TR_SESSIONID VARCHAR2(32);
      TR_SQL_ID VARCHAR2(13);
      TR_SQL VARCHAR2(60);
      TR_VERSION_NO NUMBER;
      TR_N NUMBER;
      TR_STMT CLOB := NULL;
      TR_SQL_TEXT ORA_NAME_LIST_T;
BEGIN
      TR_EVENT_ID := SYS_GUID();
      --获取用户信息
      SELECT NVL(SYS_CONTEXT(‘USERENV‘,‘TERMINAL‘),‘‘),--客户端操作系统终端的名称
             NVL(SYS_CONTEXT(‘USERENV‘,‘IP_ADDRESS‘),‘‘),--客户端操作系统终端的名称
             NVL(SYS_CONTEXT(‘USERENV‘,‘CURRENT_USER‘),‘‘),--当前SESSION拥有权限的用户的名称(比如说当前SESSION是SYS,但是正在执行SYSTEM.MYPROC,那么CURRENT_USER就是SYSTEM)
             NVL(SYS_CONTEXT(‘USERENV‘,‘CURRENT_USERID‘),‘‘),--当前SESSION拥有的权限的用户的ID
             NVL(SYS_CONTEXT(‘USERENV‘,‘SESSION_USER‘),‘‘),--SESSION所属的用户名
             NVL(SYS_CONTEXT(‘USERENV‘,‘SESSION_USERID‘),‘‘),--当前SESSION所属的用户ID
             NVL(SYS_CONTEXT(‘USERENV‘,‘PROXY_USER‘),‘‘),--打开当前SESSION的用户的名称
             NVL(SYS_CONTEXT(‘USERENV‘,‘PROXY_USERID‘),‘‘),--打开当前SESSION的用户的ID
             NVL(SYS_CONTEXT(‘USERENV‘,‘CURRENT_SCHEMA‘),‘‘),--当前SESSION缺省的SCHEMA名称
             NVL(SYS_CONTEXT(‘USERENV‘,‘HOST‘),‘‘),--客户端的主机名称
             NVL(SYS_CONTEXT(‘USERENV‘,‘OS_USER‘),‘‘),--客户端的操作系统用户名
             NVL(SYS_CONTEXT(‘USERENV‘,‘SESSIONID‘),‘‘)--SESSION的ID
      INTO TR_TERMINAL,TR_IPADDR,TR_CUR_USER,TR_CUR_USERID,TR_SE_USER,TR_SE_USERID,TR_PROXY_USER,TR_PROXY_USERID,
           TR_CUR_SC,TR_HOST,TR_OS_USER,TR_SESSIONID
      FROM DUAL;

      --获取DDL SQL语句,如果语句过长无法全部获得,可以根据SQL_ID查询
      BEGIN
           SELECT SQL_TEXT,SQL_ID INTO TR_SQL,TR_SQL_ID
           FROM V$OPEN_CURSOR
           WHERE UPPER(SQL_TEXT) LIKE ‘ALTER%‘
                 OR UPPER(SQL_TEXT) LIKE ‘CREATE%‘
                 OR UPPER(SQL_TEXT) LIKE ‘DROP%‘;

           TR_N := ORA_SQL_TXT(TR_SQL_TEXT);

           FOR I IN 1 .. TR_N LOOP
             TR_STMT := TR_STMT || TR_SQL_TEXT(I);
           END LOOP;

          EXCEPTION WHEN OTHERS THEN
           TR_SQL_ID := NULL;
           TR_STMT := NULL;
      END;

      --向TB_SYSTEM_DDL_LOGS日志表中插入DDL操作记录
      IF ORA_SYSEVENT <> ‘TRUNCATE‘ AND ORA_DICT_OBJ_NAME NOT LIKE ‘SYS_C%‘ THEN
        SELECT SEQ_DDL_VERSION.NEXTVAL INTO TR_VERSION_NO FROM DUAL;
        INSERT INTO TB_SYSTEM_DDL_LOGS
              (EVENT_ID,EVENT_NAME,TERMINAL,DB_NAME,OBJECT_NAME,OBJECT_OWNER,OBJECT_TYPE,
              IS_ALTER_COLUMN,IS_DROP_COLUMN,SQL_ID,SQL_TEXT,SESSION_ID,
              CURRENT_USER,CURRENT_USERID,SESSION_USER,SESSION_USERID,
              PROXY_USER,PROXY_USERID,CURRENT_SCHEMA,HOST,OS_USER,IP_ADDRESS,VERSION_NO)
        VALUES (TR_EVENT_ID,ORA_SYSEVENT,TR_TERMINAL,ORA_DATABASE_NAME,ORA_DICT_OBJ_NAME,ORA_DICT_OBJ_OWNER,ORA_DICT_OBJ_TYPE,
              NULL,NULL,TR_SQL_ID,TR_STMT,TR_SESSIONID,
              TR_CUR_USER,TR_CUR_USERID,TR_SE_USER,TR_SE_USERID,
              TR_PROXY_USER,TR_PROXY_USERID,TR_CUR_SC,TR_HOST,TR_OS_USER,TR_IPADDR,TR_VERSION_NO
        );
        COMMIT;
      END IF;
END;

这个触发器中过滤了一些不必要操作,大家可以根据需求增加过滤内容

结果展示

SELECT EVENT_NAME,OBJECT_TYPE,OBJECT_NAME,OBJECT_OWNER,DDL_TIME,VERSION_NO
FROM DBADMIN.TB_SYSTEM_DDL_LOGS
ORDER BY VERSION_NO;
EVENT_NAME OBJECT_TYPE OBJECT_NAME OBJECT_OWNER DDL_TIME VERSION_NO
CREATE PACKAGE PKG_LINE_RUN BUS 04-AUG-15 28
CREATE PACKAGE BODY PKG_LINE_RUN BUS 04-AUG-15 29
CREATE PACKAGE PKG_LINE_RUN BUS 04-AUG-15 32
CREATE PACKAGE BODY PKG_LINE_RUN BUS 04-AUG-15 33
CREATE TABLE ORA_TEMP_1_DS_150103 SYS 04-AUG-15 134
DROP TABLE ORA_TEMP_1_DS_150103 SYS 04-AUG-15 136
CREATE TABLE ORA_TEMP_1_DS_150104 SYS 04-AUG-15 137
DROP TABLE ORA_TEMP_1_DS_150104 SYS 04-AUG-15 139
CREATE TABLE ORA_TEMP_1_DS_150105 SYS 04-AUG-15 140
DROP TABLE ORA_TEMP_1_DS_150105 SYS 04-AUG-15 142
CREATE TABLE ORA_TEMP_1_DS_150106 SYS 04-AUG-15 143
DROP TABLE ORA_TEMP_1_DS_150106 SYS 04-AUG-15 145
CREATE TABLE DBMS_TABCOMP_TEMP_UNCMP BUS 04-AUG-15 146
CREATE TABLE DBMS_TABCOMP_TEMP_CMP BUS 04-AUG-15 147
DROP TABLE DBMS_TABCOMP_TEMP_UNCMP BUS 04-AUG-15 148
CREATE TABLE ORA_TEMP_1_DS_150107 SYS 04-AUG-15 149
DROP TABLE ORA_TEMP_1_DS_150107 SYS 04-AUG-15 151
DROP TABLE DBMS_TABCOMP_TEMP_CMP BUS 04-AUG-15 152
CREATE TABLE ORA_TEMP_1_DS_150108 SYS 04-AUG-15 153
DROP TABLE ORA_TEMP_1_DS_150108 SYS 04-AUG-15 155
CREATE TABLE ORA_TEMP_1_DS_150109 SYS 04-AUG-15 156
DROP TABLE ORA_TEMP_1_DS_150109 SYS 04-AUG-15 158
CREATE TABLE ORA_TEMP_1_DS_150110 SYS 04-AUG-15 159

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-01 10:52:06

利用Oracle DDL触发器实现DDL监控的相关文章

47. SQL- 触发器之DDL 触发器

触发器工作原理     DDL触发器 与DML 触发器不同,DDL 触发器不会为响应针对表或视图的UPDATE.INSERT或DELETE 语句而激发. 响应多种数据定义语言(DDL) 语句而激发.主要是以CREATE.ALTER和DROP 开头的语句. DDL 触发器可用于管理任务,例如审核和控制数据库操作. DDL 触发器的作用域: l 数据库作用域 l 服务器作用域 在响应当前数据库或服务器中处理的Transact-SQL 事件时,将激发DDL 触发器.触发器的作用域取决于事件(数据库作用

DDL触发器的应用

一般来说,DML触发器可以监测得到具体对象的具体数据的变更.然而,DDL触发器则能够对一些服务器的行为作出监控,比如我们可以利用DDL触发器来做登录限制啊,做一些日志控制啊之类的. 好,然后简单粗暴上例子 首先我们做一个监控创建表的触发器,DDL触发器,一个关键点是在于 EVENTDATA() 这个函数提供的信息. CREATE TRIGGER TR_CreateTable ON ALL SERVER FOR CREATE_TABLE AS BEGIN SELECT EVENTDATA(); E

DDL触发器抓取赋权操作

近期在对接中,业务(数据挖掘同事)需要将部分账号控制到表级别,只允许部分账号访问指定的表. 而这些人员是不确定的,并且变动将较为频繁. 与对接同事沟通后采用如下方案实现: 给此同事开通此数据库的db_securityadmin角色账号,此账号可以在库级别范围内给其他用户赋予表级别权限. 新建一个数据库,并在其中新增一张记录相应操作的日志表. 赋予此账户写入log表操作(grant insert)其余权限无 新建库级别的DDL触发器,通过此触发器获取相应的权限操作变动记录(grant,deny,r

SQL Server DDL 触发器(Trigger)-- 创建数据库级别的DDL触发器

SQL Server DDL 触发器(Trigger)-- 创建数据库级别的DDL触发器 以下针对某个数据库在创建数据表时调用触发器,并将创建该数据表的用户账户写入到Windows的Event Log中. CREATE TRIGGER reminder ON DATABASE FOR CREATE_TABLE AS DECLARE @str NVARCHAR(100) SET @str=suser_sname() + N'create a new table' RAISERROR(@str,10

SQL Server DDL 触发器(Trigger)-- 创建服务器级别的DDL触发器

SQL Server DDL 触发器(Trigger)-- 创建服务器级别的DDL触发器 若是创建服务器级别的DDL触发器,只要把先前的ON DATABASE改为ON ALL SERVER,即可跟踪服务器级别的事件,使用的原理与数据库级别的DDL触发器相似,区别只在跟踪的事件不同. CREATE TRIGGER ddl_trig_login ON ALL SERVER FOR DDL_LOGIN_EVENTS AS PRINT n'ALTER LOGIN EVENT' SELECT EVENTD

SQL Server DDL 触发器(Trigger)-- 介绍

SQL Server DDL 触发器(Trigger)-- 介绍 触发器(Trigger)以往仅用在特定的对象上,如数据表.当数据维护语言(DML)的Insert.Delete.Update语法针对这些对象工作时,由系统自动调用对应的触发器,而在SQL Server 2000中增加了Instead of Trigger,通过触发器来取代原本要执行的添加.修改.删除语法,且可以设置在视图上.由于Instead of Trigger是在DML语法真的改变数据写入事务日志之前触发,因此,也称为Befo

SQL Server 存储过程版本控制-DDL触发器

存储过程版本控制-DDL触发器 –参考:存储过程版本控制 http://enjoyasp.net/?p=2431 CREATE TABLE [dbo].[ChangeLog]( [LogId] [int] IDENTITY(1,1) NOT NULL, [DatabaseName] [varchar] (256) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, [EventType] [varchar](50) COLLATE SQL_Latin1_

Oracle锁3:DDL锁

当一个正在进行的DDL操作执行在或者引用了schema对象(注)时,Data dcictionary(DDL)锁用于保护该schema对象的定义,在DDL操作执行期间仅锁定单个schema对象,数据库从不锁定整个数据字典. Oracle数据库自动地请求DDL锁,用户不能显示请求DDL锁.例如,如果用户创建一个存储过程,那么数据库自动为存储过程中引用的对象请求DDL锁,这些DDL锁防止存储过程被编译完成前这个对象被改变或者删除. 排它DDL锁 一个排它DDL锁阻止其它session获取DDL或DM

存储过程版本控制-DDL触发器

参考:http://www.sqlteam.com/article/using-ddl-triggers-in-sql-server-2005-to-capture-schema-changes USE CedarLog GO CREATE TABLE [dbo].[ChangeLog]( [LogId] [INT] IDENTITY(1,1) NOT NULL, [DatabaseName] [VARCHAR](256) NOT NULL, [EventType] [VARCHAR](50)