USEGEAR

导航

restful 服务器一个问题,看ChatGPT的威力

看看是否牛逼:

 真不是写代码的料,也没有这样的天赋,仅仅玩玩而已。

问题:客户端边缘路由中一段js代码,使用get请求一个方法,把json数据送入数据库相关表。由于种种原因导致长连接,通过资源管理器可以看到TCP连接一直挂在那里。(该问题不知道是否是伪命题,请专业人员指导)

七搞八搞,依赖Chatgpt才(应该)搞定了,否则永远不可能,如果不是永远,那么就是非常非常遥远、遥远、遥远......。

上代码:

function TUsegear.UpdateAJson2DB4ZT(aJson: string): string;  //提交Json数组到账套表
var
  Task: ITask; //用于执行异步任务
  TimeoutMs: Integer;  //超时时间,单位:毫秒(默认 5000ms = 5s)
  TaskCompletedFlag: Integer;  // ✅ 确保 TInterlocked.Exchange 线程安全 任务完成标志(0 = 未完成,1 = 已完成),用于确保线程安全
  TaskResult: string;// 最终返回的执行结果
  TaskEvent: TEvent;   //用于通知主线程任务完成,避免 Sleep(10); 造成的 CPU 轮询
begin
  Result := 'Timeout';
  TimeoutMs := 10000;
  TaskCompletedFlag := 0;  // 0 = False, 1 = True   // 任务开始时标记为未完成
  TaskResult := 'Timeout';
  TaskEvent := TEvent.Create(nil, True, False, '');

   //启动后台任务
  Task := TTask.Run(procedure
  var
    LocalQuery: TFDQuery;
    LocalConn: TFDConnection;
    ja: TJSONArray;
    jo: TJSONObject;
    LocalResult, ZTName, myTable, aSQL: string;
  begin
    LocalResult := 'Unknown Error';
    ja := nil;
    LocalConn := TFDConnection.Create(nil);
    LocalQuery := TFDQuery.Create(nil);
    try
      try
        LocalConn.DriverName := FDConnection1.DriverName;
        LocalConn.Params.Assign(FDConnection1.Params);
        // **确保复制密码和数据库信息**
        LocalConn.Params.Values['Password'] := FDConnection1.Params.Values['Password'];
        LocalConn.Params.Values['User_Name'] := FDConnection1.Params.Values['User_Name'];
        LocalConn.Params.Values['Database'] := FDConnection1.Params.Values['Database'];

        try
          LocalConn.Connected := True;  // **在任务线程里独立连接数据库**
        except
          on E: Exception do
          begin
            LocalResult := '线程数据库连接失败: - ' + E.Message;
            if Var_Log then PostLog(llError,'线程数据库连接失败: -:'+e.Message);
            Exit;
          end;
        end;



//        解析 JSON
        ja := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(aJson), 0) as TJSONArray;
        if not Assigned(ja) or (ja.Count = 0) then raise Exception.Create('Invalid or empty JSON array');

        //获取账套名称 (zt) 和目标表名 (mytable)
        jo := ja.Items[0] as TJSONObject;
        ZTName := jo.GetValue<string>('zt');

        try
          LocalConn.Connected := False; // 先确保连接断开
          LocalConn.ConnectionDefName := ZTName;
          LocalConn.Connected := True;//链接指定账套
          if Var_Log then PostLog(llHint,'线程账套数据库连接成功');
        except
          on E: Exception do
            begin
              if Var_Log then PostLog(llError, '线程账套数据库连接失败: ' + E.Message);
              Exit;
            end;
        end;

        LocalQuery.Connection := LocalConn;
        LocalQuery.CachedUpdates := True;

        myTable := jo.GetValue<string>('mytable');
        //把 JSON 转换为数据集 (Dataset) 并提交数据
        aSQL := 'SELECT * FROM ' + myTable + ' WHERE 1=2';
        LocalQuery.Open(aSQL);
        TConverter.New.JSON.Source(ja).ToDataSet(LocalQuery);
        LocalQuery.ApplyUpdates(0);
        LocalResult := 'OK';
      except
        on E: Exception do
          begin
           LocalResult := 'Error: ' + E.Message;
           if Var_Log then PostLog(llError,LocalResult);
          end;
      end;
    finally
      if Assigned(ja) then FreeAndNil(ja);
      FreeAndNil(LocalQuery);
      FreeAndNil(LocalConn);
    end;

    TThread.Synchronize(nil, procedure  //线程安全更新
    begin
      if TInterlocked.Exchange(TaskCompletedFlag, 1) = 0 then
      begin
        TaskResult := LocalResult;
        TaskEvent.SetEvent;
      end;
    end);
  end);

  try    //任务超时处理
    if not Task.Wait(TimeoutMs) then
    begin
      Task.Cancel;
      TaskEvent.SetEvent; // ✅ 让主线程立即返回
    end;
  except
    on E: Exception do
    begin
      TaskResult := 'Error: Task.Wait failed - ' + E.Message;
    end;
  end;

  //彻底释放 Task
  if Task.Status <> TTaskStatus.Completed then
  begin
    Task.Wait(1000); // 额外等待1秒,确保任务彻底结束
  end;

  if TaskEvent.WaitFor(TimeoutMs) = wrTimeout then
  begin
    TaskResult := 'Error: Event timeout reached';
  end;

  TaskEvent.Free;
  Task := nil; // ✅ 彻底释放 Task,防止意外访问
  Result := TaskResult; //主线程返回最终结果
end;

 

 

posted on 2025-03-21 18:20  USEGEAR  阅读(16)  评论(0)    收藏  举报