You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中C#协程数据库查询未按预期执行的问题求助

问题分析

你的问题核心是协程异步执行的特性——StartCoroutine启动后不会阻塞当前代码,所以getDatabaseValue里刚启动协程就立刻返回result,此时新的数据库查询还在网络请求阶段,拿到的自然是上次的旧数据。


解决方案

下面提供两种最常用的修正方式,适配不同的Unity开发习惯:

方法1:用回调函数处理异步结果(Unity传统写法)

既然是异步操作,就别指望同步返回结果,改成用回调在查询完成后拿到数据:

第一步:修改协程,添加回调参数

IEnumerator searchInDatabase(string sql, Action<string[,]> onCompleted)
{
    queryCompleted = false;
    WWWForm database = new WWWForm();
    database.AddField("sqlpost", sql);
    using (UnityWebRequest www = UnityWebRequest.Post("myDatabase", database))
    {
        yield return www.SendWebRequest();
        
        // 新增:网络请求错误判断
        if (www.result != UnityWebRequest.Result.Success)
        {
            Debug.LogError($"请求失败:{www.error}");
            onCompleted?.Invoke(null);
            yield break;
        }

        string[] entries = www.downloadHandler.text.Split(",|");
        var result = new string[entries.Length, entries[0].Split(',').Length];
        for (int i = 0; i < entries.Length; i++)
        {
            string[] parts = entries[i].Split(',');
            for (int j = 0; j < parts.Length; j++)
            {
                result[i, j] = parts[j];
            }
        }
        queryCompleted = true;
        Debug.Log("Query Completed");
        // 查询完成后调用回调返回结果
        onCompleted?.Invoke(result);
    }
}

第二步:修改调用逻辑,通过回调处理结果

void Update()
{
    if (Input.GetKeyDown(KeyCode.A)) 
    {
        GetDatabaseValueWithCallback("select * from table;", 0, 0, (value) => 
        {
            Debug.Log("getting result data");
            Debug.Log($"Result = {value}");
        });
    }
}

public void GetDatabaseValueWithCallback(string sql, int x, int y, Action<string> onValueGot)
{
    Debug.Log("Waiting 00");
    StartCoroutine(searchInDatabase(sql, (result) => 
    {
        if (result != null && x < result.GetLength(0) && y < result.GetLength(1))
        {
            onValueGot?.Invoke(result[x, y]);
        }
        else
        {
            Debug.LogWarning("索引无效或查询结果为空");
            onValueGot?.Invoke(null);
        }
    }));
}

执行顺序会完全符合你的预期:

Waiting 00
Query Completed
getting result data
Result = 2

方法2:用Async/Await(Unity 2017.2+支持)

如果你的Unity版本支持,可以用更简洁的异步语法,让代码看起来像同步逻辑:

第一步:把协程改成异步方法

async Task<string[,]> SearchInDatabaseAsync(string sql)
{
    queryCompleted = false;
    WWWForm database = new WWWForm();
    database.AddField("sqlpost", sql);
    using (UnityWebRequest www = UnityWebRequest.Post("myDatabase", database))
    {
        await www.SendWebRequest();
        
        if (www.result != UnityWebRequest.Result.Success)
        {
            Debug.LogError($"请求失败:{www.error}");
            return null;
        }

        string[] entries = www.downloadHandler.text.Split(",|");
        var result = new string[entries.Length, entries[0].Split(',').Length];
        for (int i = 0; i < entries.Length; i++)
        {
            string[] parts = entries[i].Split(',');
            for (int j = 0; j < parts.Length; j++)
            {
                result[i, j] = parts[j];
            }
        }
        queryCompleted = true;
        Debug.Log("Query Completed");
        return result;
    }
}

第二步:修改调用逻辑

void Update()
{
    if (Input.GetKeyDown(KeyCode.A)) 
    {
        GetDatabaseValueAsync("select * from table;", 0, 0);
    }
}

async void GetDatabaseValueAsync(string sql, int x, int y)
{
    Debug.Log("Waiting 00");
    var result = await SearchInDatabaseAsync(sql);
    Debug.Log("getting result data");
    if (result != null && x < result.GetLength(0) && y < result.GetLength(1))
    {
        Debug.Log($"Result = {result[x, y]}");
    }
    else
    {
        Debug.LogWarning("索引无效或查询结果为空");
    }
}

额外注意事项
  • 移除原来的全局result变量,改成方法内部创建并返回,避免多查询时的变量覆盖问题。
  • 必须添加网络请求错误判断,否则请求失败时会出现空引用异常。
  • 两种方法都彻底解决了异步执行的顺序问题,不会再拿到旧数据。

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 10:33:08