0

私の会社では SQL Server 2008 を使用しています。監査テーブルでトランザクションの問題が発生しています。

ストアドプロシージャがあります。

create proc MySP
as begin
    insert into MY_TABLE values('Value1');

    begin transaction TX_MY_SP
    -- write to audit table permanently
    insert into AUDIT_TABLE values('Value1 is inserted.'); 
    commit transaction TX_MY_SP
end

VB.net コードのブロックがあります

Using tx = New TransactionScope()
    Using conn = New SqlConnection(MY_CONN_STR)
        Using cmd = New SqlCommand("MySP", conn)
            conn.Open()
            cmd.ExecuteNonQuery()
            Throw New ApplicationException("Always throw exception.")
        End Using
    End Using
    tx.Complete()
End Using

ただし、AUDIT_TABLE に挿入されるレコードはありません。MSDN http://msdn.microsoft.com/en-us/library/ms189336.aspxで理由を見つけました

私の質問は、ストアド プロシージャを使用してレコード AUDIT_TABLE を挿入する方法です。

ありがとう!

4

3 に答える 3

1

基本的に、できることは、1 つの非同期監査/ログ システムを持つことです。したがって、監査は別のスレッドで実行され、メインのトランザクション スコープが失敗するかどうかは問題ではありません。

  1. エンタープライズ ライブラリ + MSMQ を使用する
  2. 独自の軽量非同期ログ システムを構築する (同期キューを使用する)
于 2012-01-04T06:16:23.947 に答える
0

を使用する場合、トランザクションをロールバックさせたくない場合は、スコープから出る前にメソッドTransactionScopeを呼び出す必要があります。Complete

Using tx = New TransactionScope()
    Using conn = New SqlConnection(MY_CONN_STR)
        Using cmd = New SqlCommand("MySP", conn)
            conn.Open()
            cmd.ExecuteNonQuery()
            'Throw New ApplicationException("Always throw exception.")
        End Using
    End Using

    tx.Complete() ' <---- Here

End Using
于 2011-03-03T23:05:47.237 に答える
0

ロールバックされたトランザクション内のすべての操作もロールバックされます。そうしないと、トランザクションの原子性が損なわれます。監査しているアクティビティがロールバックされていることを考えると、実際には監査をロールバックする必要がある可能性が非常に高くなります。

それにもかかわらず、特定のデバッグ ケースのように、現在のトランザクションの範囲外で操作を記録する必要がある正当なケースがあります。ユーザーが構成可能なイベント クラスのイベント通知を使用、イベント通知をアクティブ化する手順を実行して監査を記録するために使用するなど、既知の回避策があります。プロファイラー イベントはトランザクション スコープ外で生成されるため、監査レコードはロールバックされません。sp_trace_generateevent

:setvar dbname testdb
:on error exit

set nocount on;
use master;

if exists (
    select * from sys.server_event_notifications
    where name = N'audit')
begin
    drop event notification audit on server;
end 
go

if db_id('$(dbname)') is not null
begin
    alter database [$(dbname)] set single_user with rollback immediate;
    drop database [$(dbname)];
end
go

create database [$(dbname)];
go

alter authorization on database::[$(dbname)] to [sa];
go

use [$(dbname)];
go

create queue audit;
create service audit on queue audit (
    [http://schemas.microsoft.com/SQL/Notifications/PostEventNotification]);
go  

create table audit_table (
    Time datetime not null,
    TextData nvarchar(256) not null);
go

create procedure usp_audit
as
begin
declare @h uniqueidentifier, @mt sysname, @mb varbinary(max), @mx xml;
begin transaction;
receive top(1) @h = conversation_handle,
    @mt = message_type_name,
    @mb = message_body
from audit;
if (@mt = N'http://schemas.microsoft.com/SQL/Notifications/EventNotification')
begin
    select @mx = cast(@mb as xml);
    insert into audit_table (Time, TextData)
    values (
        @mx.value(N'(/EVENT_INSTANCE/PostTime)[1]', N'datetime'),
        @mx.value(N'(/EVENT_INSTANCE/TextData)[1]', N'nvarchar(256)'));
end
else if (@mt = N'http://schemas.microsoft.com/SQL/ServiceBroker/Error'
    or @mt = N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog')
begin
    end conversation @h;
end 
commit
end 
go

alter queue audit
    with activation (
        status = on,
        procedure_name = usp_audit,
        max_queue_readers = 1,
        execute as owner);
go      

create event notification audit
on server for USERCONFIGURABLE_0
to service N'audit', N'current database';
go

begin transaction;
exec sp_trace_generateevent 82, N'this was inserted from a rolled back';
rollback
go

waitfor delay '00:00:05';
select * from audit_table;
go
于 2011-03-04T05:37:40.663 に答える