Как мне следить за изменениями в базе данных от единства, не заливая сетевой адаптер?

У меня есть веб-сервер, который содержит базу данных SQL. На этом сервере / базе данных есть два «пользователя». Одним из них является фактический пользователь, которому они будут отправлять изменения через UnityWebRequest, используя HTTP: Post. Это внесет изменения в базу данных.

У меня есть другая система, которая также находится в Unity, о которой нужно уведомлять или каким-либо образом отслеживать каждый раз, когда вносятся изменения в конкретную таблицу в базе данных. Я не знаю, как следить за изменениями в таблице, не делая выборочных обращений к базе данных.

Что я пробовал

У меня есть функция единства, которая вызывает веб-сервер через HTTP: Post. Веб-сервер заходит в бесконечный цикл, делая вызовы к базе данных что-то вроде

$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']);
}
}

Это поддерживает веб-сервер и делает слишком много обращений к базе данных.

Я хотел бы, чтобы Unity могла сделать один вызов веб-серверу, который задает ему определенное состояние, веб-сервер будет сравнивать указанное состояние с базой данных до тех пор, пока база данных не изменится, а затем, как только изменения в БД откликнутся на единицу с обновленным состоянием. Я хочу быть в состоянии сделать это, не делая миллион вызовов SELECT для базы данных в секунду.

Код единства


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);
}
}
}
}

0

Решение

Конечно, вы можете и всегда должны ждать в Unity UnityWebRequest заканчивать! Вы должны всегда использовать, например, сопрограммная

И чем вы можете, например, добавьте временной сдвиг, чтобы вы не делали новый запрос прямо сейчас, но, возможно, подождите несколько секунд.

Я лично также добавил бы обратные вызовы для ответа, который делает его более гибким и многократно используемым, например.

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);
}
}

Теперь вы можете назвать это, например, за ожидание через 2 секунды после последнего запроса законченный

// ...

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);
}

или также сделать то же самое, используя лямбда-выражения

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
});

Даже если вы не хотите timeOffset По крайней мере, это ожидает завершения каждого запроса, прежде чем начинать следующий, поэтому вашему серверу нужно только выполнить один запрос к БД и вернуть либо успех, либо ошибку.

В вашем случае я бы в любом случае ответил с успехом (200) (потому что ошибка должна отправляться только в том случае, если на сервере действительно была ошибка), но либо отправляю пустой string или какой-то предопределенный, который вы можете проверить в Unity (например, например, "!NO_CHANGE!").

так на стороне сервера без цикла что-то вроде, например

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

чем вы могли бы позже проверить это в Unity

if(string.Equals(success, "!NO_CHANGE!")) return;
0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]