Quellcode durchsuchen

!1786 添加简单的重试机制,解决并发报错问题。
Merge pull request !1786 from CyrusZhou/v2

zuohuaijun vor 10 Monaten
Ursprung
Commit
c6aa0a1906

+ 45 - 8
Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarSetup.cs

@@ -4,6 +4,9 @@
 //
 // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
 
+using Microsoft.Data.Sqlite;
+using SqlSugar;
+using System.Data.Common;
 using DbType = SqlSugar.DbType;
 
 namespace Admin.NET.Core;
@@ -480,7 +483,10 @@ public static class SqlSugarSetup
         foreach (var dbColumn in dbColumns.Where(c => !c.IsPrimarykey && entityInfo.Columns.All(u => u.DbColumnName != c.DbColumnName)))
         {
             dbColumn.IsNullable = true;
-            dbProvider.DbMaintenance.UpdateColumn(entityInfo.DbTableName, dbColumn);
+            Retry(() =>
+            {
+                dbProvider.DbMaintenance.UpdateColumn(entityInfo.DbTableName, dbColumn);
+            }, maxRetry: 3, retryIntervalMs: 1000);
         }
     }
 
@@ -491,14 +497,17 @@ public static class SqlSugarSetup
     /// <param name="entityType">实体类型</param>
     private static void InitializeTable(SqlSugarScopeProvider dbProvider, Type entityType)
     {
-        if (entityType.GetCustomAttribute<SplitTableAttribute>() == null)
-        {
-            dbProvider.CodeFirst.InitTables(entityType);
-        }
-        else
+        Retry(() =>
         {
-            dbProvider.CodeFirst.SplitTables().InitTables(entityType);
-        }
+            if (entityType.GetCustomAttribute<SplitTableAttribute>() == null)
+            {
+                dbProvider.CodeFirst.InitTables(entityType);
+            }
+            else
+            {
+                dbProvider.CodeFirst.SplitTables().InitTables(entityType);
+            }
+        }, maxRetry: 3, retryIntervalMs: 1000);
     }
 
     /// <summary>
@@ -656,4 +665,32 @@ public static class SqlSugarSetup
                 db.CodeFirst.SplitTables().InitTables(entityType);
         }
     }
+
+    /// <summary>
+    /// 简单的重试机制
+    /// </summary>
+    /// <param name="action"></param>
+    /// <param name="maxRetry"></param>
+    /// <param name="retryIntervalMs"></param>
+    private static void Retry(Action action, int maxRetry, int retryIntervalMs)
+    {
+        int attempt = 0;
+        while (true)
+        {
+            try
+            {
+                action();
+                return;
+            }
+            catch (SqliteException ex) when (ex.SqliteErrorCode == 5) // SQLITE_BUSY
+            {
+                if (++attempt >= maxRetry)
+                {
+                    Log.Error($"简单的重试机制:{ex.Message}"); throw;
+                }
+                Log.Information($"数据库忙,正在重试... (尝试 {attempt}/{maxRetry})");
+                Thread.Sleep(retryIntervalMs);
+            }
+        }
+    }
 }

+ 4 - 3
Admin.NET/Admin.NET.Web.Entry/wwwroot/template/Service.cs.vm

@@ -292,6 +292,7 @@ public class @(Model.ClassName)Service : IDynamicApiController, ITransient
         }
     @:}
     @:
+    @:private static readonly object _@(Model.LowerClassName)ImportLock = new object();
     @:/// <summary>
     @:/// 导入@(Model.BusName)记录 💾
     @:/// </summary>
@@ -300,7 +301,7 @@ public class @(Model.ClassName)Service : IDynamicApiController, ITransient
     @:[ApiDescriptionSettings(Name = "Import"), HttpPost, NonUnify, UnitOfWork]
     @:public IActionResult ImportData([Required] IFormFile file)
     @:{
-        @:lock (this)
+        @:lock (_@(Model.LowerClassName)ImportLock)
         @:{
             var dictTableField = Model.TableField.Where(x => x.WhetherImport == "Y" && x.EffectType == "DictSelector") ?? default;
             foreach (var column in dictTableField){
@@ -368,8 +369,8 @@ public class @(Model.ClassName)Service : IDynamicApiController, ITransient
                         @:.ToStorage();
 
                     @:
-                    @:storageable.BulkCopy();
-                    @:storageable.BulkUpdate();
+                    @:storageable.AsInsertable.ExecuteCommand();// 不存在插入
+                    @:storageable.AsUpdateable.ExecuteCommand();// 存在更新
                     @:
                     @:// 标记错误信息
                     @:markerErrorAction.Invoke(storageable, pageItems, rows);