ฉันอยากจะแนะนำรูปแบบเหมือนรูปแบบจากการจัดการข้อยกเว้นและธุรกรรมซ้อน :
create procedure [usp_my_procedure_name]
as
begin
set nocount on;
declare @trancount int;
set @trancount = @@trancount;
begin try
if @trancount = 0
begin transaction
else
save transaction usp_my_procedure_name;
-- Do the actual work here
lbexit:
if @trancount = 0
commit;
end try
begin catch
declare @error int, @message varchar(4000), @xstate int;
select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
if @xstate = -1
rollback;
if @xstate = 1 and @trancount = 0
rollback
if @xstate = 1 and @trancount > 0
rollback transaction usp_my_procedure_name;
raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ;
end catch
end
รูปแบบนี้ตรวจสอบXACT_STATE()
ใน catch block เพื่อป้องกันการทำธุรกรรมที่ไม่สามารถทำได้ :
ธุรกรรมที่ไม่สามารถยอมรับได้และ XACT_STATE
หากมีข้อผิดพลาดที่สร้างขึ้นในบล็อก TRY ทำให้สถานะของธุรกรรมปัจจุบันไม่ถูกต้องธุรกรรมจะถูกจัดประเภทเป็นธุรกรรมที่ไม่สามารถยอมรับได้ ข้อผิดพลาดที่มักจะจบการทำธุรกรรมนอกบล็อกลองทำธุรกรรมที่จะเข้าสู่สถานะที่ไม่สามารถยอมรับได้เมื่อเกิดข้อผิดพลาดภายในบล็อกลอง ธุรกรรมที่ไม่สามารถยอมรับได้สามารถดำเนินการอ่านหรือทำธุรกรรมย้อนกลับเท่านั้น ธุรกรรมไม่สามารถดำเนินการคำสั่ง Transact-SQL ใด ๆ ที่จะสร้างการดำเนินการเขียนหรือการทำธุรกรรม COMMIT ฟังก์ชัน XACT_STATE คืนค่า -1 ถ้าธุรกรรมถูกจัดประเภทเป็นธุรกรรมที่ไม่สามารถยอมรับได้ เมื่อแบตช์เสร็จสิ้น Database Engine จะย้อนกลับธุรกรรมที่ไม่สามารถใช้งานได้ หากไม่มีการส่งข้อความแสดงข้อผิดพลาดเมื่อธุรกรรมเข้าสู่สถานะที่ไม่สามารถยอมรับได้ เมื่อแบตช์เสร็จสิ้นข้อความผิดพลาดจะถูกส่งไปยังแอปพลิเคชันไคลเอนต์ สิ่งนี้บ่งชี้ว่าตรวจพบธุรกรรมที่ไม่สามารถยอมรับได้และย้อนกลับ
รหัสของคุณกำลังตรวจสอบ@@TRANCOUNT
ในตำแหน่งที่ไม่สามารถเป็น 0 ได้โดยใช้การผสมผสานของข้อความ PRINT ที่ให้ข้อมูลและชุดผลลัพธ์ SELECT สำหรับการสื่อสารที่ประสบความสำเร็จ แต่ไม่ได้จัดการข้อผิดพลาดที่สามารถกู้คืนได้ ในอุดมคติแล้วข้อยกเว้นควรเผยแพร่ไปยังลูกค้าในกรณีนี้ไปยังงานตัวแทน (เช่นการจับของคุณควรเพิ่มใหม่)