如何在不充斥NIC的情况下监视数据库中的更改

I have a web server which contains a sql database. There are two "users" to this server/database. One is the actual user where they will submit changes through a UnityWebRequest using HTTP:Post. This will make changes to the database.

I have another system that is also in Unity, that needs to be notified, or somehow monitor for whenever a change is made to a specific table in a database. I don't know how to monitor the table for changes without constantly making select calls to the database.

What I've tried

I have a unity function which calls the webserver through HTTP:Post. The webserver goes into an infinite while loop making calls to the database something like

$variable = $_REQUEST['variable_to_monitor'];
$stmt = $pdo->prepare("SELECT variable_to_monitor FROM table_name;")
while(true){
    $stmt->execute();
    results = $stmt->fetchAll()[0];
    if ($variable != results['variable_to_monitor']){
        die(results['variable_to_monitor']);
    }
}

This holds up the webserver and is making too many calls to the database.

I would like for Unity to be able to make a single call to a web server giving it a given state, the web server will compare said state to database until the database changes, then once the db changes respond to unity with the updated state. I want to be able to do this without making a million SELECT calls to a database per second.

Unity Code


    void Update()
    {
        if(hasResponse)
        {
            hasResponse = false;
            StartCoroutine(SendRequest());
        }
    }

    IEnumerator SendRequest(WWWForm form = null, Action<string> callback = null)
    {
        if(null == form) form = new WWWForm();
        form.AddField("request", "monitor_variable");
        form.AddField("variable_to_monitor", this.variable_to_monitor);

        UnityWebRequest www = UnityWebRequest.Post(url, form);
        yield return www.SendWebRequest();

        if (www.isNetworkError)
        {
            Debug.Log("Network Error");
        }
        else if (www.isHttpError)
        {
            Debug.Log("Http Error");
        }
        else
        {
            if(null == callback)
            {
                Debug.Log(www.downloadHandler.text);
            }
            else
            {
                if (!www.downloadHandler.text.Contains("New Request Started"))
                {
                    hasResponse = true;
                    callback(www.downloadHandler.text);
                }
                else
                {
                    Debug.Log(www.downloadHandler.text);
                }
            }
        }
    }
doufei2662
doufei2662 在PHP中可能重复的异步函数调用
一年多之前 回复
doutang3815
doutang3815 是的,我在问题中读到了这个,但我究竟是怎么回事?(码)
一年多之前 回复
dongqian3198
dongqian3198 使用UnityWebRequest.Post();
一年多之前 回复
duansha6410
duansha6410 你如何在Unity打电话?
一年多之前 回复

1个回答

Of course you can and always should wait in Unity for the UnityWebRequest to finish! You should allways use e.g. a Coroutine

And than you can as well e.g. add a time offset so you don't make a new request right ahead but maybe wait a few seconds.

I personally would also add callbacks for the response which makes it way more flexible and reusable e.g.

public void MakeRepeatedRequests(string url, float timeOffset, Action<string> successCallback, Action<string> errorCallback)
{
    StartCoroutine(RepeatedRequestRoutine(url, timeOffset, successCallback, errorCallback);
}

private IEnumerator RepeatedRequestRoutine(string url, float timeOffset, Action<string> successCallback, Action<string> errorCallback)
{
    // No worries this still looks like a while loop (well it is ^^)
    // but the yield makes sure it doesn't block Unity's UI thread
    while(true)
    {
        // Configure your request
        var request = UnityWebRequest.Post(url);

        // Make the request and wait until the it has finished (has a response or timeout)
        // a yield kind of tells this routine to leave, let Unity render this frame
        // and continue from here in the next frame
        yield return request.SendWebRequest();

        if(request.isNetworkError || request.isHttpError) 
        {
            errorCallback?.Invoke(request.error);
        }
        else 
        {
            successCallback?.Invoke(request.downloadHandler.text);
        }

        // Now wait for the timeOffset
        yield return new WaitForSeconds(timeOffset);
    }
}

Now you can call it e.g. for waiting 2 seconds after the last request finished

// ...

    MakeRepeatedRequests ("http://example.com", 2.0f, OnSuccess, OnError);

// ...

private void OnSuccess(string success)
{
    Debug.LogFormat(this, "Nice it worked! Server said:/"{0}/"", success);

    // Do something e.g. using success
}

private void OnError(string error)
{
    Debug.LogFormat(this, "Oh no, request failed with \"{0}\"", error);
}

or also do the same thing using lambda expressions

MakeRepeatedRequests ("http://example.com", 2.0f, 

    success =>
    {
        Debug.LogFormat(this, "Nice it worked! Server said:/"{0}/"", success);

        // Do something e.g. using success
    }, 

    error =>
    {
        Debug.LogFormat(this, "Oh no, request failed with \"{0}\"", error);

        // Do something else
    });

Even if you don't want the timeOffset this at least waits for every request to finish before starting the next one so your server only has to make one DB query and either return a success or an error.

In your case I would respond with a success (200) anyway (because error should be sent only if the server really had an error) but either send an empty string or some predefined one you can check for in Unity (something like e.g. "!NO_CHANGE!").

so on the server side without a loop something like e.g.

results = "SELECT * FROM table_name;"
if ($_REQUEST['variable_name'] != results['variable_name']){
    echo results['variable_name'];
} else {
    echo "!NO_CHANGE!";
}

than you could later in Unity check it

if(string.Equals(success, "!NO_CHANGE!")) return;
dongtang7347
dongtang7347 正如我所说,我不会让服务器等待。我会让Unity在某些时间间隔内发出请求,如果有变化同时发送它,否则以“NO_Change”响应,所以Unity知道服务器仍然有效但是 那里没有变化。 似乎没有像JavaScript这样的东西,你可以保持连接几分钟,如果你想...但正如已经说过,我根本不会在服务器上等待。
一年多之前 回复
dsa45664
dsa45664 我把Unity标签放在一起,因为使用UnityWebRequest有不同的选项,而不是它是一个网络浏览器进行后期调用。 我很确定如果我使用网络浏览器我可以使用ajax或类似的东西 - 虽然我从未使用过ajax所以我不知道
一年多之前 回复
douba05167
douba05167 哦,但为什么Unity3d标签,如果这实际上只是关于PHP? 请注意,我很确定你不能等到你得到一个回复​​然后回答Unity ...你总是不得不从Unity方面重复打电话,要么没有回应,要么回应更改。 =>你必须反复请求,所以使用上述方法有什么问题?
一年多之前 回复
dongpao5658
dongpao5658 对不起,如果我的问题不够明确,我的问题不在于团结。 我要做的是让团结发送webrequest(我已经实现了,你提供了)并让网络服务器在5分钟后响应,或者在数据库中进行了更改。 我不想让团结每隔半秒左右发送一次请求,而是每5分钟发送一次请求,或者每当它得到响应时。 我有代码,但我的问题是我不知道如何编写一个PHP脚本,等待响应,直到数据库发生了变化。 现在我在我的问题中让php脚本进入while循环
一年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐