我正在尝试为在 Web 应用程序、SQL Server 代理作业和手动运行对数据库的查询中执行的操作创建审计跟踪。我正在尝试使用触发器来捕获某些表上的更新、插入和删除。
总的来说,这个过程是有效的。例如,用户在 Web 应用程序中执行更新,触发器将更新的数据写入我定义的审计跟踪表,包括执行操作的人的用户名。从 Web 应用程序或手动查询的角度来看,这工作得很好,但我们也有几十个 SQL Server 代理作业,我想捕获哪个运行了特定的查询。每个代理作业都使用相同的用户名运行。这也可以正常工作并将用户名正确输入到表中,但我找不到哪个作业调用此查询。
我当前的“解决方案”是找出触发时当前正在运行的作业,因为其中之一必须是正确的。使用:
CREATE TABLE #xp_results
(
job_id UNIQUEIDENTIFIER NOT NULL,
last_run_date INT NOT NULL,
last_run_time INT NOT NULL,
next_run_date INT NOT NULL,
next_run_time INT NOT NULL,
next_run_schedule_id INT NOT NULL,
requested_to_run INT NOT NULL, -- BOOL
request_source INT NOT NULL,
request_source_id sysname COLLATE database_default NULL,
running INT NOT NULL, -- BOOL
current_step INT NOT NULL,
current_retry_attempt INT NOT NULL,
job_state INT NOT NULL
)
INSERT INTO #xp_results
EXECUTE master.dbo.xp_sqlagent_enum_jobs 1, 'sa'
SELECT @runningJobs = STUFF((SELECT ',' + j.name
FROM #xp_results r
INNER JOIN msdb..sysjobs j ON r.job_id = j.job_id
WHERE running = 1
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
DROP TABLE #xp_results
我运行了一个特定的作业来测试它似乎可以工作,因为任何正在运行的 OTHER 作业都将列在 中@runningJobs
,但它不会记录运行它的作业。我假设当触发器运行时,作业已经完成。
有没有办法我可以找出什么工作调用了触发触发器的查询?
编辑:我尝试更改SELECT
上面的查询以获取在过去 2 分钟内运行或当前正在运行的任何作业。SQL 查询现在是:
SELECT @runningJobs = STUFF((SELECT ',' + j.name
FROM #xp_results r
INNER JOIN msdb..sysjobs j ON r.job_id = j.job_id
WHERE (last_run_date = CAST(REPLACE(LEFT(CONVERT(VARCHAR, getdate(), 120), 10), '-', '') AS INT)
AND last_run_time > CAST(REPLACE(LEFT(CONVERT(VARCHAR,getdate(),108), 8), ':', '') AS INT) - 200)
OR running = 1
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
当我运行作业时,然后在作业运行时运行上述查询,将返回正确的作业。但是,当 SSIS 包运行时,无论是通过 SQL Server 代理作业还是在 SSIS 中手动运行,@runningJobs
都不会填充并仅返回NULL
.
所以我现在认为这是 SSIS 和master.dbo.xp_sqlagent_enum_jobs
. 还有其他想法吗?
编辑#2:实际上不要认为这是权限错误。此代码下方有一条INSERT
语句,如果它是权限错误,则该INSERT
语句不会运行,因此审核行不会添加到数据库中。因此,由于数据库中添加了一行,只是没有runningJobs
填充该字段。奇怪的时代。
编辑#3:我只是想澄清一下,我正在寻找一个不需要我进入每项工作并改变任何东西的解决方案。有太多的工作使这成为一个可行的解决方案。