Allied Modders en español

Versión completa: MySQL: datos que se borran?
Actualmente estas viendo una versión simplificada de nuestro contenido. Ver la versión completa con el formato correcto.
Tengo dos servidores que usan guardado MySQL con bastantes jugadores diariamente y desde hace años.

Pues bien, resulta que a veces (muy rara vez, quizás 1 cada 3 meses) a algún jugador se le reinician sus datos a 0.

He revisado en numerosas ocasiones el sistema de cargado y guardado de datos por si en algún lugar reiniciaba yo las variables y luego le guardaba sus datos con las variables reiniciadas, pero esto nunca ocurre o no puede darse...

Por esto recurro al foro, para saber si alguno de ustedes han tenido algún problema de este tipo o similar con guardado SQLite o MySQL.

Quizás alguna interrupción en el servidor? Alguna caída de su conexión?

Muchas gracias
Si tienes el sistema hecho "correctamente", lo mas viable que veo sería que los datos no se carguen correctamente, por ende las variables quedarían en 0, y al momento de guardar los datos se "reinicien".

No se si me di a entender correctamente Nothingdohere
Te recomiendo utilizar transacciones mediante procedimientos almacenados, en vez de tirar la query desde el plugin.
(05/09/2019, 07:05 PM)kikizon2 escribió: [ -> ]lo mas viable que veo sería que los datos no se carguen correctamente

Eso pensé el año pasado y justo le puse un log para cuando no encuentre datos.

En total ha detectado dos jugadores y ninguno de ellos estaba relacionado con el problema que explico. Así que esa opción la descarto.

(05/09/2019, 11:05 PM)INTIFADA escribió: [ -> ]Te recomiendo utilizar transacciones mediante procedimientos almacenados, en vez de tirar la query desde el plugin.

Explíquese más Insecure
(06/09/2019, 09:49 AM)RauliTop escribió: [ -> ]
(05/09/2019, 07:05 PM)kikizon2 escribió: [ -> ]lo mas viable que veo sería que los datos no se carguen correctamente

Eso pensé el año pasado y justo le puse un log para cuando no encuentre datos.

En total ha detectado dos jugadores y ninguno de ellos estaba relacionado con el problema que explico. Así que esa opción la descarto.

(05/09/2019, 11:05 PM)INTIFADA escribió: [ -> ]Te recomiendo utilizar transacciones mediante procedimientos almacenados, en vez de tirar la query desde el plugin.

Explíquese más Insecure

Las transacciones son una unidad única de trabajo, en la cual, si el estado de la transacción fue éxitosa, los cambios pasan a ser permanentes en la base de datos, de otra forma tenes que revertir los cambios que realizó dicha transacción, con la palabra "rollback".

No es mucho más que eso, son utilizadadas por ejemplo en bancos cuando se debe garantizar coherencia de los datos de los clientes.

Un ejemplo muy básico para entenderlo es por ejemplo cuando haces una transferencia bancaría de un monto "x" de una cuenta a otra, tenes que garantizar de que al cliente 1 se le remuevan 100 dolares y a la cuenta 2 se le sumen 100 dolares. Pero que pasa si al cliente 1 le removes 100 dolares y de alguna forma se cuelga la base de datos u ocurre otro tipo de problema haciendo que no se le sumen 100 dolares a la cuenta 2, tenemos un problema. Y este es el problema de la consistencia de los datos que necesitan bancos, o empresas que manejan dinero ya que en una cuenta restaste un monto pero no sumaste en la otra cuenta.

Para esto aparecen las transacciones, que mas o menos sería algo asi

Código PHP:
START TRANSACTION;

UPDATE accounts SET ammount ammount 100 WHERE id 100;
UPDATE accounts SET ammount ammount 100 WHERE id 101;

COMMIT

Simplemente le estas diciendo al motor MySQL que estás iniciando una transacción en la cual le restas 100 dolares al cliente con id 100 y sumando 100 dolares al cliente con id 101.

Pero como está en modo transacción, los cambios no se van a efectuar hasta que no ejecutes un "COMMIT". De esta manera podrías salvar que le restes dinero a un cliente y no se lo sumes a otro. Podría también explicar cosas más técnicas pero creo no tiene mucho sentido, si necesitas más información sobre transacciones tenes la documentación oficial de MySQL sobre transacciones y procedimientos almacenados.

Yo uso procedimientos almacenados con transacciones en mi sistema de cuentas ya que si tenes una o mas tablas en las cuales tengas que meter una foreign key del id de la cuenta del jugador creada y no logran insertarse correctamente pierdo la consistencia de los datos, haciendo que mi base de datos se rompa, para evitar eso decido revertir los cambios mediante la transacción, kickear al jugador del servidor y que cree su cuenta nuevamente.

TRANSACCIONES: https://dev.mysql.com/doc/refman/8.0/en/commit.html
PROCEDIMIENTOS ALMACENADOS: https://dev.mysql.com/doc/connector-net/...dures.html
Seguramente sea el guardar datos el problema, cuando haces UPDATE a una variable que se setea siempre en 0, me pasaba con el top mix anteriormente.
Ejemplo:

Código PHP:
public client_putinserver(id) {
    
g_frags[id] = 0;
    
    
formatex(Querycharsmax(Query), "SELECT * FROM tabla WHERE nombre=santi"); //los carga
    
sql_query(idQuery);
}

public 
client_disconnect(id) {
    
formatex(Querycharsmax(Query), "UPDATE tabla SET frags='%d' WHERE nombre=santi"g_frags[id]); //los updatea pero con los frags en "0" o en los que sumo ahora.
    
sql_query(idQuery);
    } 
Entonces ahora vamos a un ejemplo más concreto.
santi, tiene 17 frags guardados, cuando vuelve a entrar mato a 5, pero magicamente en vez de sumar el 17 + 5 se le ponen los 5 debido al mal uso de UPDATE en la tabla. Entonces si haces lo que dijo el de arriba que lo explica a la perfección el uso, harías un: "frags(17) = frags(17) + 5", el resultado, 22 frags guardados en la base de datos.
Otra solución, que no sé si es de fiarse o no, es hacer lo siguiente.
Usar g_frags[id] para todo absolutamente, para cargar/guardar los datos. Me refiero a lo siguiente:
Código PHP:
Acá empiezo a sumar g_frags[idcuando ya esta matando a un player.

public 
event_death_msg()
{
    new 
atacante read_data(1);
    new 
victima read_data(2);

    if(
is_user_connected(atacante) && is_user_alive(atacante))
    {
        if(
atacante != victima
        {
            
g_frags[atacante]++; 
        }
    }
}

Acá dentro del Query uso g_frags como los resultados que me esta mostrandoO sea los frags que ya tiene cargados en la base de datosLa consulta es
SELECT 
FROM 'tabla' WHERE nombre=santi
public QueryData(failstateerror[], errnumdata[], sizeFloat:queuetime
{
    if(
failstate != TQUERY_SUCCESS
    {
        
log_to_file("QueryLoadData.log",  "%s: [num: %d] [err: %s]"dataerrnumerror);
        return 
PLUGIN_HANDLED;
    }
    
    static 
id;
    
id data[0];
    
    if(!
is_user_connected(id))
        return 
PLUGIN_HANDLED;
    
    if(
mysql_num_results()) 
        
g_frags[id] = mysql_read_result(1);
    else    
Data_MySQL(idINSERT);
    
    return 
PLUGIN_CONTINUE;
}

Ahora la siguiente consulta:
UPDATE tabla SET frags='g_frags[id]' WHERE nombre=santi
El update lo hago en otra query
esta query se va a llamar "QuerySaveData"Dentro de la QuerySaveData del UPDATE hago:
g_frags[id] = mysql_read_result(1); 

Así logre yo primero en hacer que los datos no se me pierdan en sí.
Cabe aclarar que en QuerySaveData se usa el "INSERT y UPDATE" y dentro de QueryData se utiliza el "SELECT"
2 handlersen el primer handler "QuerySaveData" lo utilizo para INSERTAR y UPDATEAR los datos y en el segundo handler lo utilizo para CARGAR los datos
(07/09/2019, 09:38 AM)Niper.-. escribió: [ -> ]Otra solución, que no sé si es de fiarse o no, es hacer lo siguiente.
Usar g_frags[id] para todo absolutamente, para cargar/guardar los datos.

Eso es evidentemente, sino nunca guardaría ningún dato de nadie.

El problema está en que mágicamente se vuelven a 0 los valores de una cuenta aleatoria cada cierto periodo largo de tiempo.
Supongo que será porque surge un error o retraso en la conexión.

@INTIFADA
Agradezco enormemente la información sobre las transacciones, nunca está de más saber algo nuevo.
Pero no creo que sea necesario para los datos de un servidor, debiendo de reestructurar de nuevo todas las conexiones que se realizan. Quizás si fuese a crear un nuevo sistema sí, pero por ahora no me merece la pena tanto esfuerzo.


Parece ser que el problema está en que después de guardarle los datos por desconectarse, cuando entra una nueva persona, obviamente reinicio a 0 todas las variables que guardan datos. Posteriormente, cuando esa nueva persona entra con su cuenta le pongo sus datos en las variables.

Lo único que puede pasar parece ser que:
El error puede darse cuando la consulta se demore en enviar, entra un nuevo jugador pasando las variables a 0 y, finalmente, la consulta se envía.
NO debería pasar, porque la consulta se envió antes, pero algo así debe ser.

SOLUCIÓN (a espera de confirmación):
He omitido el paso de reiniciar a 0 las variables, dado que no es necesario porque al entrar con su cuenta se cargan sus datos en las variables de nuevo y nunca llega a usar las variables con los datos antiguos.
También he tomado precauciones en caso de que no encuentre datos de su cuenta, entonces sí le reinicio las variables a 0. (aunque esto nunca debería pasar).

Realicé esta solución en otro servidor con menos datos. Y parece ser que nunca más se dio el error, o nadie se ha quejado de que se le borraron datos.