您的位置:首页 > 数据库

SQL Server DDL触发器运用

2015-12-18 10:14 453 查看


一.本文所涉及的内容(Contents)

本文所涉及的内容(Contents)
背景(Contexts)
基础知识(Rudimentary Knowledge)
DDL运用场景(DDL Scene)
补充说明(Addon)
疑问(Questions)
参考文献(References)


二.背景(Contexts)

  说到触发器,大家都会想到这样的使用场景:当一个表的数据修改了,运用DML触发插入或者更新到其它表中;那DDL触发器(SQL Server 2005引入的新功能)会运用到什么场景中呢?本文将为你讲述4种运用DDL触发器的场景:

  1) 禁止用户修改和删除表;

  2) 禁止用户删除数据库;

  3) 记录和监控某数据库所有的DDL操作;

  4) 把DDL操作信息以邮件的形式主动发送通知和预警;


三.基础知识(Rudimentary Knowledge)

  DDL触发器是由修改数据库对象的 DDL 语句(如以 CREATE、ALTER 或 DROP)激发。

  DDL触发器支持BEFORE和AFTER事件触发器,并在数据库或模式级运行。通常,DDL触发器用于监控数据库中的重要事件。有时用它们来监控错误代码。错误代码可能会执行破坏数据库或使数据库不稳定的活动。更常见的情况是:在开发、测试和stage系统中用它们来了解和监控数据库活动的动态。

  当监控GRANT和REVOKE权限语句时,它们也是有效的安全工具。


四.DDL运用场景(DDL Scene)

(一) 首先我们来看一个简单的例子:创建数据库DDL_DB和一个名为DatabaseLog的表,现在创建一个DDL触发器:禁止用户修改和删除表,并进行提醒。执行下面的SQL脚本进行测试。

--Script1:
--创建测试数据库
USE MASTER
GO
CREATE DATABASE DDL_DB

--创建DDL触发器记录表
USE DDL_DB
GO
CREATE TABLE [dbo].[DatabaseLog](
[DatabaseLogID] [int] IDENTITY(1,1) NOT NULL,
[PostTime] [datetime] NOT NULL,
[ServerName] [sysname] NOT NULL,
[LoginName] [sysname] NOT NULL,
[DatabaseUser] [sysname] NOT NULL,
[DatabaseName] [sysname] NOT NULL,
[Schema] [sysname] NULL,
[Object] [sysname] NULL,
[TSQL] [nvarchar](max) NOT NULL,
[Event] [sysname] NOT NULL,
[XmlEvent] [xml] NOT NULL,
CONSTRAINT [PK_DatabaseLog_DatabaseLogID] PRIMARY KEY NONCLUSTERED
(
[DatabaseLogID] ASC
) ON [PRIMARY]
) ON [PRIMARY]

--Script2:
--创建DDL触发器:禁止修改或者删除数据表
CREATE TRIGGER DDL_TableTrigger
ON DATABASE
FOR DROP_TABLE, ALTER_TABLE
AS
PRINT '对不起,您不能对数据表进行操作,请联系DBA'
ROLLBACK ;

--测试删除表
USE DDL_DB
GO
DROP TABLE [DatabaseLog]




(Figure1:创建数据库级别的DDL)



(Figure2:返回的提示信息)



(Figure3:SSMS返回的提示信息)

创建数据库级别的DDL之后会出现在数据库触发器列表中,如Figure1;当执行删除表的Drop等DDL命令的时候,就会出现Figure2的提示信息;如果是在SSMS中删除表则会出现Figure3的提示信息。

(二) 在上面的基础上再进行扩展,创建一个DDL触发器:禁止用户删除数据库,并进行提醒。

--Script3:
--禁止SQL Server服务器里删除数据库
CREATE TRIGGER DDL_DataBaseTrigger
ON ALL SERVER
FOR DROP_DATABASE
AS
PRINT '对不起,您不能删除数据库,请联系DBA'
ROLLBACK;

--测试删除数据库
USE MASTER
GO
DROP DATABASE [DDL_DB]




(Figure4:创建服务器级别的DDL)



(Figure5:返回的提示信息)



(Figure6:SSMS返回的提示信息)

创建服务器级别的DDL之后会出现在服务器对象-触发器的列表中,如Figure4;当执行删除数据库的Drop等DDL命令的时候,就会出现Figure5的提示信息;如果是在SSMS中删除数据库则会出现Figure6的提示信息。

(三) 很多时候在程序开发阶段是不会禁用对数据库的修改的,这些时候我们更希望是记录数据库的修改信息,方便对信息进行跟踪检查。使用 EVENTDATA 函数,可以捕获有关激发 DDL 触发器的事件的信息,此函数返回 xml 值。

前面已经创建了数据表DatabaseLog,创建下面的DDL_DatabaseLog触发器,每当数据库发生DDL事件,DDL触发器就会把相关的DDL信息插入到DatabaseLog表,信息包括操作的时间,操作人,操作的SQL等。

执行Script5测试脚本,返回Figure7的信息,查询DatabaseLog表,返回的记录有2条,一条是创建表信息,一条是删除表信息,如Figure8、Figure9所示。

--Script4:
--创建当前数据库的DDL触发器
USE DDL_DB
GO
-- =============================================
-- Author:        <听风吹雨>
-- Create date:    <2013.05.03>
-- Description:    <记录数据库DDL操作>
-- Blog:        <http://www.cnblogs.com/gaizai/>
-- =============================================
CREATE TRIGGER [DDL_DatabaseLog]
ON DATABASE
FOR DDL_DATABASE_LEVEL_EVENTS AS
BEGIN
SET NOCOUNT ON;
DECLARE @data XML;
DECLARE @schema sysname;
DECLARE @object sysname;
DECLARE @eventType sysname;
SET @data = EVENTDATA();
SET @eventType = @data.value('(/EVENT_INSTANCE/EventType)[1]', 'sysname');
SET @schema = @data.value('(/EVENT_INSTANCE/SchemaName)[1]', 'sysname');
SET @object = @data.value('(/EVENT_INSTANCE/ObjectName)[1]', 'sysname')

IF @object IS NOT NULL
PRINT '  ' + @eventType + ' - ' + @schema + '.' + @object;
ELSE
PRINT '  ' + @eventType + ' - ' + @schema;
IF @eventType IS NULL
PRINT CONVERT(nvarchar(max), @data);
INSERT [DDL_DB].[dbo].[DatabaseLog](
[PostTime],
[ServerName],
[LoginName],
[DatabaseUser],
[DatabaseName],
[Schema],
[Object],
[TSQL],
[Event],
[XmlEvent])
VALUES(
GETDATE(),
@data.value('(/EVENT_INSTANCE/ServerName)[1]', 'sysname'),
@data.value('(/EVENT_INSTANCE/LoginName)[1]', 'sysname'),
CONVERT(sysname, CURRENT_USER),
@data.value('(/EVENT_INSTANCE/DatabaseName)[1]', 'sysname'),
CONVERT(sysname, @schema),
CONVERT(sysname, @object),
@data.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'nvarchar(max)'),
@eventType,
@data
);
END;

--Script5:测试DDL记录
--禁用DDL 触发器
DISABLE TRIGGER DDL_TableTrigger ON DATABASE;
GO
CREATE TABLE TestTable (a int)
GO
DROP TABLE TestTable;
GO

SELECT * FROM [DatabaseLog];
GO




(Figure7:返回的提示信息)



(Figure8:DatabaseLog表前半部分信息)



(Figure9:DatabaseLog表后半部分信息)

(四) 我们可以使用DDL触发器主动监控DDL语句的执行,当有对数据库执行DDL就会触发,我们把这些信息保存到表中,并且把操作用户的HostName和修改的T-SQL以邮件的形式发送到指定的邮件。关于设置数据库邮件可以参考:SQL Server 数据库邮件。发送邮件的效果如Figure10。邮件部分参考:MS
SQL监控数据库的DDL操作

--Script5:
--创建当前数据库的DDL触发器
USE DDL_DB
GO
-- =============================================
-- Author:        <听风吹雨>
-- Create date:    <2013.05.03>
-- Description:    <记录数据库DDL操作,发送邮件预警>
-- Blog:        <http://www.cnblogs.com/gaizai/>
-- =============================================
CREATE TRIGGER [DDL_DatabaseLog]
ON DATABASE
FOR DDL_DATABASE_LEVEL_EVENTS AS
BEGIN
SET NOCOUNT ON;
DECLARE @data XML;
DECLARE @schema sysname;
DECLARE @object sysname;
DECLARE @eventType sysname;
DECLARE @databaseName sysname;
DECLARE @tableHTML  NVARCHAR(MAX);
SET @data = EVENTDATA();
SET @eventType = @data.value('(/EVENT_INSTANCE/EventType)[1]', 'sysname');
SET @schema = @data.value('(/EVENT_INSTANCE/SchemaName)[1]', 'sysname');
SET @object = @data.value('(/EVENT_INSTANCE/ObjectName)[1]', 'sysname');
SET @databaseName = @data.value('(/EVENT_INSTANCE/DatabaseName)[1]', 'sysname');

IF @object IS NOT NULL
PRINT '  ' + @eventType + ' - ' + @schema + '.' + @object;
ELSE
PRINT '  ' + @eventType + ' - ' + @schema;
IF @eventType IS NULL
PRINT CONVERT(nvarchar(max), @data);
INSERT [DDL_DB].[dbo].[DatabaseLog](
[PostTime],
[ServerName],
[LoginName],
[DatabaseUser],
[DatabaseName],
[Schema],
[Object],
[TSQL],
[Event],
[XmlEvent])
VALUES(
GETDATE(),
@data.value('(/EVENT_INSTANCE/ServerName)[1]', 'sysname'),
@data.value('(/EVENT_INSTANCE/LoginName)[1]', 'sysname'),
CONVERT(sysname, CURRENT_USER),
@databaseName,
CONVERT(sysname, @schema),
CONVERT(sysname, @object),
@data.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'nvarchar(max)'),
@eventType,
@data
);

SET @tableHTML =
N'<H1>DDL Event</H1>' +
N'<table border="0">' +
N'<tr><th>PostTime</th><th>ServerName</th><th>LoginName</th><th>DatabaseUser</th><th>DatabaseName</th><th>Object</th>' +
N'<th>TSQL</th></tr>' +
CAST((SELECT
td = [PostTime],'',
td = [ServerName],'',
td = [LoginName],'',
td = [DatabaseUser],'',
td = [DatabaseName],'',
td = [Object],'',
td = TSQL,''
FROM [DDL_DB].[dbo].[DatabaseLog]
WHERE DatabaseLogID =(SELECT MAX(DatabaseLogID) FROM [DDL_DB].[dbo].[DatabaseLog])
FOR XML PATH('tr'), TYPE) AS NVARCHAR(MAX)) +
N'</table>';

DECLARE @subjectStr  NVARCHAR(MAX);
SET @subjectStr = 'DDL Event - DataBaseName: ' + @databaseName;
EXEC msdb.dbo.sp_send_dbmail
@profile_name = 'DataBase_DDL_Event',
@recipients='bbspediy@126.com',
@subject = @subjectStr,
@body = @tableHTML,
@body_format = 'HTML';
END;




(Figure10:邮件收到的预警)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: