Apakah ada cara untuk meneruskan informasi ke pemicu Hapus sehingga dapat mengetahui siapa yang menghapus catatan?
Ya: dengan menggunakan fitur yang sangat keren (dan kurang dimanfaatkan) disebut CONTEXT_INFO
. Ini pada dasarnya adalah memori sesi yang ada di semua ruang lingkup dan tidak terikat oleh transaksi. Ini dapat digunakan untuk meneruskan info (info apa pun - yah, apa pun yang sesuai dengan ruang terbatas) untuk memicu serta bolak-balik antara panggilan sub-proc / EXEC. Dan saya telah menggunakannya sebelumnya untuk situasi yang sama persis ini.
Uji dengan yang berikut ini untuk melihat cara kerjanya. Perhatikan bahwa saya masuk CHAR(128)
sebelum CONVERT(VARBINARY(128), ..
. Ini untuk memaksa pad-kosong agar lebih mudah untuk mengkonversi kembali VARCHAR
ketika keluar CONTEXT_INFO()
karena VARBINARY(128)
padded dengan 0x00
s.
SELECT CONTEXT_INFO();
-- Initially = NULL
DECLARE @EncodedUser VARBINARY(128);
SET @EncodedUser = CONVERT(VARBINARY(128),
CONVERT(CHAR(128), 'I deleted ALL your records! HA HA!')
);
SET CONTEXT_INFO @EncodedUser;
SELECT CONTEXT_INFO() AS [RawContextInfo],
RTRIM(CONVERT(VARCHAR(128), CONTEXT_INFO())) AS [DecodedUser];
Hasil:
0x492064656C6574656420414C4C20796F7572207265636F7264732120484120484121202020202020...
I deleted ALL your records! HA HA!
MENEMPATKAN SEMUA BERSAMA:
Aplikasi harus memanggil prosedur tersimpan "Hapus" yang dilewati di UserName (atau apa pun) yang menghapus catatan. Saya berasumsi ini sudah model yang digunakan karena sepertinya Anda sudah melacak operasi Sisipkan dan Perbarui.
Prosedur "Hapus" yang disimpan tidak:
DECLARE @EncodedUser VARBINARY(128);
SET @EncodedUser = CONVERT(VARBINARY(128),
CONVERT(CHAR(128), @UserName)
);
SET CONTEXT_INFO @EncodedUser;
-- DELETE STUFF HERE
Pemicu audit tidak:
-- Set the INT value in LEFT (currently 50) to the max size of [UserWhoMadeChanges]
INSERT INTO AuditTable (IdOfRecordedAffected, UserWhoMadeChanges)
SELECT del.ID, COALESCE(
LEFT(RTRIM(CONVERT(VARCHAR(128), CONTEXT_INFO())), 50),
'<unknown>')
FROM DELETED del;
Harap perhatikan bahwa, seperti yang @SeanGallardy tunjukkan dalam komentar, karena prosedur lain dan / atau kueri ad hoc menghapus catatan dari tabel ini, ada kemungkinan bahwa:
CONTEXT_INFO
belum diatur dan masih NULL
:
Untuk alasan ini saya telah memperbarui di atas INSERT INTO AuditTable
untuk menggunakan nilai COALESCE
default. Atau, jika Anda tidak ingin default dan memerlukan nama, maka Anda dapat melakukan sesuatu yang mirip dengan:
DECLARE @UserName VARCHAR(50); -- set to the size of AuditTable.[UserWhoMadeChanges]
SET @UserName = LEFT(RTRIM(CONVERT(VARCHAR(128), CONTEXT_INFO())), 50);
IF (@UserName IS NULL)
BEGIN
ROLLBACK TRAN; -- cancel the DELETE operation
RAISERROR('Please set UserName via "SET CONTEXT_INFO.." and try again.', 16 ,1);
END;
-- use @UserName in the INSERT...SELECT
CONTEXT_INFO
telah disetel ke nilai yang bukan UserName yang valid, dan karenanya mungkin melebihi ukuran AuditTable.[UserWhoMadeChanges]
bidang:
Untuk alasan ini saya menambahkan LEFT
fungsi untuk memastikan bahwa apa pun yang diambil CONTEXT_INFO
tidak akan merusak INSERT
. Seperti disebutkan dalam kode, Anda hanya perlu mengatur 50
ukuran UserWhoMadeChanges
bidang yang sebenarnya.
PEMBARUAN UNTUK SQL SERVER 2016 DAN BARU
SQL Server 2016 menambahkan versi yang disempurnakan dari memori per-sesi ini: Session Context. Konteks Sesi baru pada dasarnya adalah tabel hash pasangan Key-Value dengan tipe "Key" sysname
(yaitu NVARCHAR(128)
) dan "Value" SQL_VARIANT
. Berarti:
- Sekarang ada pemisahan nilai sehingga lebih kecil kemungkinannya bertentangan dengan kegunaan lain
- Anda dapat menyimpan berbagai jenis, tidak perlu lagi khawatir tentang perilaku aneh ketika mendapatkan kembali nilai melalui
CONTEXT_INFO()
(untuk detail, silakan lihat posting saya: Mengapa Tidak CONTEXT_INFO () Mengembalikan Nilai Tepat yang Ditetapkan oleh SET CONTEXT_INFO? )
- Anda mendapatkan lebih banyak ruang: maks 8000 byte per "Nilai", hingga total 256kb di semua kunci (dibandingkan dengan 128 byte maks
CONTEXT_INFO
)
Untuk detailnya, silakan lihat halaman dokumentasi berikut:
SUSER_SNAME()
adalah kunci untuk mendapatkan siapa yang menghapus data.