【发布时间】:2019-08-04 21:52:05
【问题描述】:
我正在开发一个游戏数据库。我有一个由游戏客户端在传送、登录、注销、死亡等过程中执行的存储过程。游戏客户端是硬编码的,我无法编辑。
我正在我的程序中做一些事情,例如如果角色登录到游戏,然后将项目添加到角色的库存中。
对于每种不同类型的进程,我都有IF 块,并且每个“IF”块中都有TRY...CATCH 块,以便能够处理我的过程中的任何错误。
那么,我的问题是,以这种方式使用 TRY...CATCH 块是否有意义?或者我应该使用SET XACT_ABORT ON 语句而不是TRY...CATCH?哪一个更好?顺便说一句,IF块出现任何错误的情况,该块必须完全是ROLLBACK。
另外,我的程序被游戏客户端高度执行。游戏中有近800个在线角色总是在移动并执行我的程序。它应该尽可能快地执行。
ALTER PROCEDURE [dbo].[_AddLogChar]
@CharID INT,
@EventID TINYINT,
@Data1 INT,
@Data2 INT,
@strPos VARCHAR(64),
@Desc VARCHAR(128)
AS
---- !!! KILL PROCEDURE !!! ----
IF (@EventID NOT IN (4,6,20))
BEGIN
RETURN 0;
END
---- BATTLE ARENA | ACADEMY ----
IF (@EventID = 20)
BEGIN
BEGIN TRY
BEGIN TRANSACTION TRAN_Battle_Arena
-- Declaration of variables for battle area conditions
DECLARE @CharInBattle VARCHAR(64) = SUBSTRING(@strPos, 15, 6)
IF (@CharInBattle IN ('0x7edc','0x7edb','0x7ed7','0x7ed3','0x7dd3','0x7ada','0x7ad8','0x7ad7','0x7ad5','0x7ad4','0x79db','0x79da','0x79d8','0x79d7','0x79d5','0x79d4','0x74d6','0x73d7','0x73d6','0x73d5','0x73d4','0x72d7','0x72d6','0x72d5','0x72d4'))
BEGIN
DECLARE @KillingCharname VARCHAR(50) = (SELECT SUBSTRING(@Desc,(PATINDEX('%(%', @Desc)) + 1, ((PATINDEX('%)%', @Desc)) - (PATINDEX('%(%', @Desc))) - 1))
DECLARE @KilledCharname VARCHAR(64) = (SELECT CharName16 FROM SRO_VT_SHARD.._Char WITH (NOLOCK) WHERE CharID = @CharID)
IF((@KillingCharname IS NOT NULL) AND (@KilledCharname IS NOT NULL))
BEGIN
INSERT INTO LOG_BattleHonorRank (KillingCharname, KilledCharname, BattleRegion)
VALUES (@KillingCharname, @KilledCharname, @CharInBattle)
UPDATE SRO_VT_SHARD.._TrainingCamp
SET GraduateCount = (GraduateCount + 1),
EvaluationPoint = EvaluationPoint + 5
WHERE ID = (SELECT CampID FROM SRO_VT_SHARD.._TrainingCampMember WITH (NOLOCK) WHERE CharName = @KillingCharname)
UPDATE SRO_VT_SHARD.._TrainingCamp
SET EvaluationPoint = EvaluationPoint - 6
WHERE ID = (SELECT CampID FROM SRO_VT_SHARD.._TrainingCampMember WITH (NOLOCK) WHERE CharName = @KilledCharname)
END
END
COMMIT TRANSACTION TRAN_Battle_Arena
END TRY
BEGIN CATCH
SELECT
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage;
ROLLBACK TRANSACTION TRAN_Battle_Arena
END CATCH
RETURN 1;
END
---- JOB SYSTEM ----
IF(@EventID=6 AND (SELECT [Level] FROM SRO_VT_SHARD.dbo._CharTrijob WHERE CharID=@CharID)=7)
BEGIN
BEGIN TRY
BEGIN TRANSACTION TRAN_Job_System
---------------------------------------------------------------------------------------------------
-- Declaration of variables
---------------------------------------------------------------------------------------------------
DECLARE @Charname16 VARCHAR(64)=(SELECT Charname16 FROM SRO_VT_SHARD.dbo._Char WITH (NOLOCK) WHERE CharID=@CharID)
DECLARE @traderJID INT=(SELECT UserJID FROM SRO_VT_SHARD.dbo._User WITH (NOLOCK) WHERE CharID=@CharID)
DECLARE @SkillID INT
DECLARE @JobBuffLevel INT
---------------------------------------------------------------------------------------------------
-- Check users have any information in SK_Silk or not, if not then begin to addition
---------------------------------------------------------------------------------------------------
IF NOT EXISTS(SELECT JID FROM [SRO_VT_ACCOUNT].[dbo].[SK_Silk] WHERE JID=@traderJID)
BEGIN
INSERT INTO [SRO_VT_ACCOUNT].[dbo].[SK_Silk] (JID, silk_own, silk_gift, silk_point) VALUES(@traderJID, 0, 0, 0);
END
---------------------------------------------------------------------------------------------------
-- Check users have any information in LOG_CharJobStatus or not, if not then begin to addition
---------------------------------------------------------------------------------------------------
IF NOT EXISTS(SELECT CharID FROM SRO_VT_LOG..LOG_CharJobStatus WHERE CharID=@CharID)
BEGIN
INSERT INTO SRO_VT_LOG..LOG_CharJobStatus (CharID, Charname, RestartCount, ObtainedSilk) VALUES(@CharID, @Charname16, 0, 0)
END
---------------------------------------------------------------------------------------------------
-- Begin to add reward silk, restart count, obtained silk & job coins information
---------------------------------------------------------------------------------------------------
UPDATE [SRO_VT_ACCOUNT].[dbo].[SK_Silk] SET silk_own=(silk_own+10) WHERE JID=@traderJID;
UPDATE SRO_VT_LOG..LOG_CharJobStatus SET RestartCount=(RestartCount+1), ObtainedSilk=(ObtainedSilk+10), [Date]=GETDATE() WHERE CharID=@CharID
EXEC SRO_VT_SHARD.dbo._ADD_ITEM_EXTERN @Charname16,'ITEM_ETC_SD_TOKEN_02',4,0
---------------------------------------------------------------------------------------------------
-- Check users restart count modulus, if modulus 10 equals to 0, then begin to add advanced elixir scroll
---------------------------------------------------------------------------------------------------
IF((SELECT (RestartCount % 10) FROM SRO_VT_LOG..LOG_CharJobStatus WHERE CharID=@CharID)=0)
BEGIN
UPDATE SRO_VT_LOG..LOG_CharJobStatus SET Obtained_Advanced_Elixir=(Obtained_Advanced_Elixir+1), [Date]=GETDATE() WHERE CharID=@CharID
EXEC SRO_VT_SHARD.dbo._ADD_ITEM_EXTERN @Charname16,'ITEM_ETC_VENUS_ADVANCED_ELIXIR_SCROLL',1,0
END
---------------------------------------------------------------------------------------------------
-- Check users restart count modulus, if modulus 5 equals to 0, then begin to add job buff
---------------------------------------------------------------------------------------------------
IF((SELECT (RestartCount % 5) FROM SRO_VT_LOG..LOG_CharJobStatus WHERE CharID=@CharID)=0)
BEGIN
IF EXISTS (SELECT JobID FROM SRO_VT_SHARD.._TimedJob WITH (NOLOCK) WHERE CharID=@CharID AND JobID IN (33791,33792,33793,33794,33795,33796,33797,33798,33799,33800))
BEGIN
DELETE FROM SRO_VT_SHARD.._TimedJob WHERE CharID=@CharID AND JobID IN (33791,33792,33793,33794,33795,33796,33797,33798,33799,33800)
END
IF((SELECT BuffLevel FROM SRO_VT_LOG..LOG_CharJobStatus WHERE CharID=@CharID)<=10)
BEGIN
UPDATE SRO_VT_LOG..LOG_CharJobStatus SET BuffLevel=(BuffLevel+1), [Date]=GETDATE() WHERE CharID=@CharID
END
SET @JobBuffLevel=(SELECT BuffLevel FROM SRO_VT_LOG..LOG_CharJobStatus WHERE CharID=@CharID)
SELECT @SkillID=
(CASE
WHEN @JobBuffLevel=1 THEN 33791
WHEN @JobBuffLevel=2 THEN 33792
WHEN @JobBuffLevel=3 THEN 33793
WHEN @JobBuffLevel=4 THEN 33794
WHEN @JobBuffLevel=5 THEN 33795
WHEN @JobBuffLevel=6 THEN 33796
WHEN @JobBuffLevel=7 THEN 33797
WHEN @JobBuffLevel=8 THEN 33798
WHEN @JobBuffLevel=9 THEN 33799
WHEN @JobBuffLevel>=10 THEN 33800
ELSE 0
END)
IF (NOT EXISTS (SELECT JobID FROM SRO_VT_SHARD.._TimedJob WHERE JobID=@SkillID AND CharID=@CharID) AND (@SkillID>0))
BEGIN
INSERT INTO SRO_VT_SHARD.._TimedJob VALUES (@CharID,0,@SkillID,(SELECT DATEDIFF(SECOND,'19700101 00:00:00:000',(SELECT DATEADD(HOUR,72,GETUTCDATE())))),0,1,0,0,0,0,0,0,0,0)
END
END
---------------------------------------------------------------------------------------------------
-- Restart to users job level
---------------------------------------------------------------------------------------------------
UPDATE SRO_VT_SHARD.._CharTrijob SET [Level]=1, [Exp]=0, Contribution=0 WHERE CharID=@CharID
COMMIT TRANSACTION TRAN_Job_System
END TRY
BEGIN CATCH
SELECT
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage;
ROLLBACK TRANSACTION TRAN_Job_System
END CATCH
END
----==========================================================================================================----
-------------------------------------------- SILKPERPERIOD -----------------------------------------------
IF(@EventID=4 OR @EventID=6)
BEGIN
BEGIN TRY
BEGIN TRANSACTION TRAN_SilkPerPeriod
---------------------------------------------------------------------------------------------------
-- For login state
---------------------------------------------------------------------------------------------------
IF (@EventID=4)
BEGIN
IF NOT EXISTS(SELECT CharID FROM LOG_CharInOut WHERE CharID=@CharID)
BEGIN
INSERT INTO LOG_CharInOut (CharID,Char_Name,Is_Online,In_Date) VALUES(@CharID, (SELECT CharName16 FROM SRO_VT_SHARD.._Char WITH(NOLOCK) WHERE CharID=@CharID), 1, GETDATE());
END
IF EXISTS(SELECT CharID FROM LOG_CharInOut WHERE CharID=@CharID)
BEGIN
UPDATE LOG_CharInOut SET Is_Online=1, In_Date=GETDATE() WHERE CharID=@CharID
END
END
---------------------------------------------------------------------------------------------------
-- For logout state
---------------------------------------------------------------------------------------------------
IF (@EventID=6)
BEGIN
DECLARE @SilkQuantity INT=1 -- Quantity of silk to be given within the specified period.
DECLARE @ReqTime INT=60 -- The minimum required online period in minutes to be awarded for the silk reward.
UPDATE LOG_CharInOut SET Is_Online=0, Out_Date=GETDATE() WHERE CharID=@CharID
DECLARE @JID INT=(SELECT UserJID FROM SRO_VT_SHARD.dbo._User WITH (NOLOCK) WHERE CharID=@CharID)
DECLARE @LastOnlineTime INT=(SELECT DATEDIFF(MINUTE,(SELECT In_Date FROM LOG_CharInOut WHERE CharID=@CharID),(SELECT Out_Date FROM LOG_CharInOut WHERE CharID=@CharID)))
UPDATE LOG_CharInOut SET Last_OnlineTime=@LastOnlineTime, Total_OnlineTime=Total_OnlineTime+@LastOnlineTime WHERE CharID=@CharID
DECLARE @TotalOnlineTime INT, @UsedOnlineTime INT;
SELECT @TotalOnlineTime=Total_OnlineTime , @UsedOnlineTime=Used_OnlineTime FROM LOG_CharInOut WHERE CharID=@CharID
IF NOT EXISTS(SELECT JID FROM SRO_VT_ACCOUNT..SK_Silk WHERE JID=@JID)
BEGIN
INSERT INTO SRO_VT_ACCOUNT..SK_Silk (JID, silk_own, silk_gift, silk_point) VALUES(@JID, 0, 0, 0);
END
IF EXISTS(SELECT JID FROM SRO_VT_ACCOUNT..SK_Silk WHERE JID=@JID)
BEGIN
IF ((CONVERT(INT,@TotalOnlineTime-@UsedOnlineTime)/@ReqTime)>0)
BEGIN
UPDATE SRO_VT_ACCOUNT..SK_Silk SET silk_point=silk_point+(CONVERT(INT,((@TotalOnlineTime-@UsedOnlineTime)/@ReqTime))*@SilkQuantity) WHERE JID=@JID
UPDATE LOG_CharInOut SET Used_OnlineTime=Used_OnlineTime+((CONVERT(INT,((@TotalOnlineTime-@UsedOnlineTime)/@ReqTime)))*@ReqTime) WHERE CharID=@CharID
END
END
END
COMMIT TRANSACTION TRAN_SilkPerPeriod
END TRY
BEGIN CATCH
SELECT
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage;
ROLLBACK TRANSACTION TRAN_SilkPerPeriod
END CATCH
END
----==========================================================================================================----
---------------------------------------------- STAT RESET ------------------------------------------------
IF(@EventID=6 AND EXISTS(SELECT CharID FROM SRO_VT_LOG..LOG_CharStat WHERE CharID=@CharID))
BEGIN
DECLARE @RebirthCountForStat INT=(SELECT RebirthCount FROM SRO_VT_LOG..LOG_CharRebirth WITH (NOLOCK) WHERE CharID=@CharID)
DECLARE @MaxLevel TINYINT=(SELECT MaxLevel FROM SRO_VT_SHARD.._Char WITH (NOLOCK) WHERE CharID=@CharID)
DECLARE @StatPoint SMALLINT, @RemainStatPoint SMALLINT
SET @StatPoint=
(CASE
WHEN @RebirthCountForStat IS NULL THEN @MaxLevel+19
WHEN @RebirthCountForStat <= 5 THEN @MaxLevel+(@RebirthCountForStat*6)+19
WHEN @RebirthCountForStat > 5 THEN @MaxLevel+49
ELSE @MaxLevel+19
END)
SET @RemainStatPoint = (@MaxLevel*3)-3
UPDATE SRO_VT_SHARD.._Char SET Strength=@StatPoint, Intellect=@StatPoint, RemainStatPoint=@RemainStatPoint WHERE CharID=@CharID
DELETE FROM SRO_VT_LOG..LOG_CharStat WHERE CharID=@CharID
END
----==========================================================================================================----
-------------------------------------------- REBIRTH SYSTEM ----------------------------------------------
IF(@EventID=6)
BEGIN
DECLARE @RebirthCount INT=(SELECT RebirthCount FROM SRO_VT_LOG..LOG_CharRebirth WHERE CharID=@CharID)
DECLARE @Is_Active TINYINT=(SELECT Is_Active FROM SRO_VT_LOG..LOG_CharRebirth WHERE CharID=@CharID)
IF(@Is_Active=1 AND @RebirthCount<=5)-- Rebirth Count Limitation-1
BEGIN
UPDATE SRO_VT_SHARD.._Char SET
CurLevel=1,
MaxLevel=1,
ExpOffset=0,
SExpOffset=0,
Strength=20+(@RebirthCount*6),
Intellect=20+(@RebirthCount*6),
RemainSkillPoint=0,
RemainStatPoint=0
WHERE SRO_VT_SHARD.._Char.CharID=@CharID
DELETE CS FROM SRO_VT_SHARD.._RefSkill RS INNER JOIN SRO_VT_SHARD.._CharSkill CS ON CS.CharID=@CharID AND RS.ID=CS.SkillID AND RS.ReqCommon_MasteryLevel1<=110 AND RS.ID NOT IN (1,70,40,2,8421,9354,9355,11162,9944,8419,8420,11526,10625)
UPDATE SRO_VT_SHARD.._CharSkillMastery SET [Level]=0 WHERE CharID=@CharID AND [Level]<=110
UPDATE SRO_VT_LOG..LOG_CharRebirth SET Is_Active=0 WHERE CharID=@CharID
END
END
----==========================================================================================================----
--################################################################################################################```
【问题讨论】:
-
在这个存储过程中发生了太多事情,首先我会将这段代码分成三个单独的存储过程来处理事件 ID 4、6 和 20,然后有一个单独的 TRY 块,具体取决于调用三个存储过程之一的 EventID 值和一个 CATCH 块以回滚在 try 块中调用的存储过程。最佳实践是在存储过程中做一件事。代码更易于管理,并且在需要时可以轻松添加更多功能。
-
@M.Ali 设置 xact_abort on vs try..catch 怎么样?
-
总是尝试捕捉。
-
必读Error and Transaction Handling in SQL Server,作者是 Erland Sommarskog。你最好同时使用
SET XACT_ABORT ON和TRY CATCH。 -
我同意@VladimirBaranov。
XACT_ABORT ON的好处也在于它会在查询超时的情况下立即回滚事务,此时CATCH块没有被执行。
标签: sql-server tsql stored-procedures