install.sql 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. IF OBJECT_ID(N'dbo.XiaoshuSyncCommandLog', N'U') IS NULL
  2. BEGIN
  3. CREATE TABLE dbo.XiaoshuSyncCommandLog (
  4. Id bigint IDENTITY(1,1) NOT NULL PRIMARY KEY,
  5. IdempotencyKey nvarchar(128) NOT NULL,
  6. Operation nvarchar(100) NOT NULL,
  7. Actor nvarchar(200) NOT NULL,
  8. Reason nvarchar(500) NOT NULL,
  9. PayloadJson nvarchar(max) NOT NULL,
  10. ResultJson nvarchar(max) NULL,
  11. State varchar(20) NOT NULL,
  12. CreatedAt datetime2(3) NOT NULL CONSTRAINT DF_XiaoshuSyncCommandLog_CreatedAt DEFAULT SYSUTCDATETIME(),
  13. CompletedAt datetime2(3) NULL,
  14. CONSTRAINT UQ_XiaoshuSyncCommandLog_Idempotency UNIQUE (IdempotencyKey)
  15. );
  16. END;
  17. GO
  18. IF OBJECT_ID(N'dbo.XiaoshuSyncChangeLog', N'U') IS NULL
  19. BEGIN
  20. CREATE TABLE dbo.XiaoshuSyncChangeLog (
  21. Id bigint IDENTITY(1,1) NOT NULL PRIMARY KEY,
  22. Dataset nvarchar(64) NOT NULL,
  23. LegacyKey bigint NOT NULL,
  24. ItemKey bigint NULL,
  25. Operation char(1) NOT NULL,
  26. ChangedAt datetime2(3) NOT NULL CONSTRAINT DF_XiaoshuSyncChangeLog_ChangedAt DEFAULT SYSUTCDATETIME(),
  27. CONSTRAINT CK_XiaoshuSyncChangeLog_Operation CHECK (Operation IN ('I','U','D'))
  28. );
  29. CREATE INDEX IX_XiaoshuSyncChangeLog_Dataset_Id ON dbo.XiaoshuSyncChangeLog(Dataset,Id) INCLUDE(LegacyKey,ItemKey,Operation,ChangedAt);
  30. END;
  31. GO
  32. CREATE OR ALTER TRIGGER dbo.XiaoshuSync_ZL_User_Changes ON dbo.ZL_User AFTER INSERT,UPDATE,DELETE AS
  33. BEGIN
  34. SET NOCOUNT ON;
  35. INSERT dbo.XiaoshuSyncChangeLog(Dataset,LegacyKey,Operation)
  36. SELECT N'users',COALESCE(i.UserID,d.UserID),CASE WHEN d.UserID IS NULL THEN 'I' WHEN i.UserID IS NULL THEN 'D' ELSE 'U' END
  37. FROM inserted i FULL OUTER JOIN deleted d ON d.UserID=i.UserID;
  38. END;
  39. GO
  40. CREATE OR ALTER TRIGGER dbo.XiaoshuSync_ZL_Node_Changes ON dbo.ZL_Node AFTER INSERT,UPDATE,DELETE AS
  41. BEGIN
  42. SET NOCOUNT ON;
  43. INSERT dbo.XiaoshuSyncChangeLog(Dataset,LegacyKey,Operation)
  44. SELECT N'nodes',COALESCE(i.NodeID,d.NodeID),CASE WHEN d.NodeID IS NULL THEN 'I' WHEN i.NodeID IS NULL THEN 'D' ELSE 'U' END
  45. FROM inserted i FULL OUTER JOIN deleted d ON d.NodeID=i.NodeID;
  46. END;
  47. GO
  48. CREATE OR ALTER TRIGGER dbo.XiaoshuSync_ZL_CommonModel_Changes ON dbo.ZL_CommonModel AFTER INSERT,UPDATE,DELETE AS
  49. BEGIN
  50. SET NOCOUNT ON;
  51. INSERT dbo.XiaoshuSyncChangeLog(Dataset,LegacyKey,ItemKey,Operation)
  52. SELECT CASE COALESCE(i.ModelID,d.ModelID)
  53. WHEN 58 THEN N'course-bindings' WHEN 54 THEN N'appointments' WHEN 59 THEN N'lessons'
  54. WHEN 56 THEN N'learning-records' WHEN 53 THEN N'practice-records' WHEN 60 THEN N'memory-records'
  55. WHEN 61 THEN N'assessments' WHEN 52 THEN N'vocabulary'
  56. WHEN 2 THEN CASE WHEN COALESCE(i.NodeID,d.NodeID)=3 THEN N'special-training' END
  57. END,
  58. COALESCE(i.GeneralID,d.GeneralID),COALESCE(i.ItemID,d.ItemID),
  59. CASE WHEN d.GeneralID IS NULL THEN 'I' WHEN i.GeneralID IS NULL THEN 'D' ELSE 'U' END
  60. FROM inserted i FULL OUTER JOIN deleted d ON d.GeneralID=i.GeneralID
  61. WHERE COALESCE(i.ModelID,d.ModelID) IN (2,52,53,54,56,58,59,60,61)
  62. AND (COALESCE(i.ModelID,d.ModelID)<>2 OR COALESCE(i.NodeID,d.NodeID)=3);
  63. END;
  64. GO
  65. DECLARE @AddonTriggers TABLE(TableName sysname,ModelID int,Dataset nvarchar(64));
  66. INSERT @AddonTriggers(TableName,ModelID,Dataset) VALUES
  67. (N'ZL_C_kcbd',58,N'course-bindings'),(N'ZL_C_order',54,N'appointments'),
  68. (N'ZL_C_skjl',59,N'lessons'),(N'ZL_C_ss',56,N'learning-records'),
  69. (N'ZL_C_lxjl',53,N'practice-records'),(N'ZL_C_gywjl',60,N'memory-records'),
  70. (N'ZL_C_cpda',61,N'assessments'),(N'ZL_C_ck',52,N'vocabulary'),
  71. (N'ZL_C_Article',2,N'special-training');
  72. DECLARE @TableName sysname,@ModelID int,@Dataset nvarchar(64),@TriggerSql nvarchar(max);
  73. DECLARE addon_cursor CURSOR LOCAL FAST_FORWARD FOR SELECT TableName,ModelID,Dataset FROM @AddonTriggers;
  74. OPEN addon_cursor; FETCH NEXT FROM addon_cursor INTO @TableName,@ModelID,@Dataset;
  75. WHILE @@FETCH_STATUS=0
  76. BEGIN
  77. SET @TriggerSql=N'CREATE OR ALTER TRIGGER dbo.'+QUOTENAME(N'XiaoshuSync_'+@TableName+N'_Changes')+N' ON dbo.'+QUOTENAME(@TableName)+N' AFTER INSERT,UPDATE,DELETE AS
  78. BEGIN
  79. SET NOCOUNT ON;
  80. WITH changed AS (SELECT ID FROM inserted UNION SELECT ID FROM deleted)
  81. INSERT dbo.XiaoshuSyncChangeLog(Dataset,LegacyKey,ItemKey,Operation)
  82. SELECT N'''+REPLACE(@Dataset,'''','''''')+N''',c.GeneralID,c.ItemID,''U''
  83. FROM changed x INNER JOIN dbo.ZL_CommonModel c ON c.ItemID=x.ID AND c.ModelID='+CONVERT(nvarchar(20),@ModelID)+
  84. CASE WHEN @ModelID=2 THEN N' AND c.NodeID=3' ELSE N'' END+N';
  85. END;';
  86. EXEC sys.sp_executesql @TriggerSql;
  87. FETCH NEXT FROM addon_cursor INTO @TableName,@ModelID,@Dataset;
  88. END;
  89. CLOSE addon_cursor; DEALLOCATE addon_cursor;
  90. GO
  91. CREATE OR ALTER PROCEDURE dbo.XiaoshuSync_ExecuteCommand
  92. @Operation nvarchar(100), @Actor nvarchar(200), @Reason nvarchar(500),
  93. @IdempotencyKey nvarchar(128), @ExpectedUpdatedAt nvarchar(50) = NULL,
  94. @PayloadJson nvarchar(max), @ResultJson nvarchar(max) OUTPUT
  95. AS
  96. BEGIN
  97. SET NOCOUNT ON; SET XACT_ABORT ON;
  98. IF ISJSON(@PayloadJson) <> 1 THROW 51000, N'写入负载必须是有效 JSON', 1;
  99. BEGIN TRANSACTION;
  100. EXEC sys.sp_getapplock @Resource=N'xiaoshu-sync-command:'+@IdempotencyKey,@LockMode='Exclusive',@LockOwner='Transaction',@LockTimeout=10000;
  101. SELECT @ResultJson=ResultJson FROM dbo.XiaoshuSyncCommandLog WHERE IdempotencyKey=@IdempotencyKey AND State='completed';
  102. IF @ResultJson IS NOT NULL BEGIN COMMIT; RETURN; END;
  103. IF NOT EXISTS (SELECT 1 FROM dbo.XiaoshuSyncCommandLog WHERE IdempotencyKey=@IdempotencyKey)
  104. INSERT dbo.XiaoshuSyncCommandLog(IdempotencyKey,Operation,Actor,Reason,PayloadJson,State) VALUES(@IdempotencyKey,@Operation,@Actor,@Reason,@PayloadJson,'processing');
  105. /* 在此调用旧站 BLL/正式存储过程,与本日志同一事务并回写 ResultJson。 */
  106. ROLLBACK;
  107. THROW 51001, N'该写入操作尚未与旧站业务逻辑绑定,已安全拒绝', 1;
  108. END;
  109. GO