¿Redis admite transacciones?
Descripción general
Creo que los estudiantes que han estudiado MySQL y otras bases de datos están familiarizados con el término transacción. Representa una serie de operaciones, ya sean todas ejecutadas o no. ¿Por qué existe tal necesidad? Mire el siguiente escenario:
Weibo es una red social de relaciones débiles. Hay dos relaciones entre usuarios: seguir y ser seguido. Por ejemplo, dos usuarios A y B. Si A sigue a B, entonces B. Debe haber A entre los seguidores. La acción de seguir debe completarse en dos pasos: agregar B a los seguidores de A; agregar A a los seguidores de B. O ambas operaciones se ejecutan correctamente o ninguna de ellas se ejecuta. De lo contrario, puede surgir una situación intolerable: A sigue a B, pero B no tiene a A entre sus seguidores.
Transferencia y remesa, suponiendo que hay dos cuentas A y B, y ahora necesita transferir 10,000 yuanes de la cuenta de A a la cuenta de B. Esta acción también requiere dos pasos para completarse: desde la cuenta de A Transferir 10,000 yuanes. ; agregue 10.000 yuanes a la cuenta de B. ¡O todas estas dos operaciones se ejecutan con éxito o ninguna de ellas se ejecuta, de lo contrario lo harán automáticamente!
Redis, como base de datos distribuida eficiente, también admite transacciones.
Transacción de Redis
Una transacción en Redis es una colección de comandos. Una transacción es la unidad de ejecución más pequeña en Redis. Todos los comandos de la transacción se ejecutan o no se ejecutan en absoluto. La implementación de transacciones de Redis requiere el uso de comandos "MULTI" y "EXEC". Estos dos comandos se envían al servidor de Redis al comienzo de la transacción, seguidos de los comandos que deben procesarse en la transacción y, finalmente, los comandos. Comando "EJEC". El comando EXEC? indica el final del comando de transacción.
Por ejemplo, use redis-cli para conectarse a redis y luego ingrese el siguiente comando en la herramienta de línea de comando:
1234567891011121314151617181920
127.0.0.1: 6379> MULTIOK127 0.0.1.6379> establecer url g.meQUEUED127.0.0.1:6379> establecer título winwill2012QUEUED127.0.0.1:6379> establecer desc javaQUEUED127.0.0.1:6379> EXEC1) OK2) OK3) OK127.0.0. 0.1:6379> 127.0.0.1:6379> obtener URL "h.me "127.0.0.1:6379> obtener título "winwill2012"127.0.0.1:6379> obtener descripción "java "127.0.1:6379>
De la salida Se puede ver que cuando se ingresa el comando MULTI, el servidor devuelve OK para indicar que la transacción se inició exitosamente y luego ingresa todos los comandos que deben ejecutarse en esta transacción. Cada comando ingresado no se ejecutará. El servidor lo ejecuta inmediatamente, pero devolverá "¡EN COLA!", Lo que indica que El comando ha sido aceptado por el servidor y guardado temporalmente. Finalmente, ingrese el comando EXEC. Todos los comandos de la transacción se ejecutarán en secuencia. el servidor finalmente devolvió tres OK a la vez. Los resultados devueltos aquí corresponden al orden de los comandos enviados, lo que indica que todos los comandos de la transacción se ejecutaron correctamente.
Para otro ejemplo, ingrese el siguiente comando en la herramienta de línea de comando:
1234567891011121314151617
127.0.0.1:6379> MULTIOK127.0.0.1:6379> set a aQUEUED127.0.0.1.6379> sett b b(Error) ERR Comando desconocido 'sett'127.0.0.1:6379> set c cQUEUED127.0.0.1:6379> EXEC(Error) EXECABORT La transacción fue descartada debido a un error anterior. .0.0.1:6379> obtener a(nil)127.0.0.1:6379> obtener b(nil)127.0.0.1:6379> obtener c(nil)127.0.0.1:6379& gt;
Y el anterior Igual que en el ejemplo, ingrese MULTI primero y luego EXEC para indicar que el comando en el medio pertenece a una transacción. La diferencia es que el comando ingresado en el medio tiene un error (la configuración se escribe como set In). De esta manera, debido a un error en el comando, otros comandos en la transacción no se ejecutan (se puede ver mediante el comando get posterior que todos los comandos en la transacción tienen el mismo comando).
Si el cliente se desconecta antes de enviar el comando EXEC, el servidor borrará la cola de transacciones y no se ejecutarán todos los comandos de la transacción. Una vez que el cliente envía el comando EXEC, todos los comandos de la transacción se ejecutarán incluso si el cliente se desconecta posteriormente porque el servidor ha guardado todos los comandos de la transacción.
Además de garantizar que todos los comandos de una transacción se ejecuten o no, las transacciones de Redis también garantizan que los comandos de una transacción se ejecuten en orden y no puedan ser insertados por otros comandos. Imagine que el cliente A necesita ejecutar varios comandos y el cliente B necesita enviar varios comandos. Si no utiliza transacciones, los comandos del cliente B pueden insertarse en varios comandos del cliente A. Si desea evitar esta situación, también puede utilizar transacciones.
Manejo de errores de transacciones de Redis
¿Cómo manejará Redis si ocurre un error de ejecución de comando en una transacción? Para responder a esta pregunta, primero debe averiguar por qué ocurrió el error de ejecución del comando:
¿Error de sintaxis? Como se muestra en el ejemplo anterior, un error de sintaxis significa que el comando no existe o que los parámetros son incorrectos
Esta situación requiere distinguir entre diferentes versiones de Redis. Las versiones de Redis anteriores a la 2.6.5 ignorarán el comando incorrecto y ejecutarán otros comandos correctos, mientras que las versiones posteriores a la 2.6.5 ignorarán todos los comandos de la transacción y no ejecutarán ningún comando, como en el ejemplo anterior (usando la versión 2.8 de Redis) < / p>
¿Error de ejecución? Los errores de tiempo de ejecución son errores que ocurren al ejecutar un comando, como usar el comando GET para obtener un valor clave de un tipo de tabla hash.
Redis no puede detectar dichos errores antes de que se ejecute el comando, por lo que dentro de la transacción, Redis acepta y ejecuta dichos comandos. Si un comando en la comida se ejecuta con un error, se seguirán ejecutando otros comandos (incluido el comando que sigue al error).
Por ejemplo, lo siguiente:
1234567891011121314
127.0.0.1:6379> MULTIOK127.0.0.1:6379> establecer clave 1QUEUED127.0.0.1:6379> clave SADD 2QUEUED127.0.0 1:6379> establecer clave 3QUEUED127.0.0.1:6379> EXEC1) OK2) (error) WRONGTYPE Operación contra una clave que contiene el tipo de valor incorrecto3) OK127.0.0.1:6379> obtener clave "3"
Las transacciones en Redis no tienen las capacidades de reversión de las bases de datos relacionales, por lo que los usuarios deben limpiar ellos mismos el desorden restante. Sin embargo, el hecho de que Redis no admita la reversión hace que las transacciones en Redis sean limpias y rápidas.
Recordando los dos tipos de errores anteriores, los errores de sintaxis se pueden detectar y manejar durante el proceso de desarrollo. Si se planifica cuidadosamente el uso de claves para los datos de Redis, no habrá problemas de discrepancia entre comandos y claves.
Comando WATCH
En el ejemplo anterior, podemos ver que todos los comandos de la transacción deben ejecutarse antes de poder obtener los resultados de cada comando, pero si el comando B en la transacción depende de ¿Qué debemos hacer con el resultado del comando anterior A? Por ejemplo, al ejecutar una función i++ similar a Java, primero se debe obtener el valor actual antes de agregar uno al valor actual. Esta situación no se puede lograr simplemente usando MULTI y EXEC presentados anteriormente, porque los comandos MULTI y EXEC se ejecutan juntos y el resultado de la ejecución de un comando no se puede usar como parámetro de ejecución de otro comando, por lo que las transacciones de Redis deben introducirse en esta vez Otro miembro de la familia: el comando WATCH
Piénsalo desde otro ángulo arriba. La ejecución de i++ se puede implementar de la siguiente manera:
Monitorear el valor de i para asegurarse de que no haya sido modificado
Obtener el valor original de i
Si durante este proceso i's Si el valor no se ha modificado, el valor actual de i será +1; de lo contrario, no se ejecutará
Esto puede evitar condiciones de carrera y garantizar que i++ se pueda ejecutar correctamente.
El comando WATCH monitorea una o más claves. Una vez que una de las claves se modifica (o elimina), la transacción no se ejecutará posteriormente y el monitoreo continuará hasta que se ejecute el comando EXEC (los comandos en la transacción lo harán). se ejecutará después de EXEC y la clave monitoreada se UNWATCH automáticamente después de ejecutar el comando EXEC)
Ejemplo:
123456789101112131415
127.0.0.1:6379> set mykey 1OK127.0.0 .1:6379> WATCH mykeyOK127.0.0.1:6379> configure mykey 2OK127.0.0.1.6379> MULTIOK127.0.0.1:6379> configure mykey 3QUEUED127.0.0.1:6379> EXEC(nil)127.0. 0.1:6379> get mykey "2"127.0.0.1:6379>
En el ejemplo anterior, primero establece el valor clave de mykey en 1, luego usa el comando WATCH para monitorear mykey y luego cambia el valor de mykey a 2, luego ingrese la transacción, establezca el valor de mykey en 3, luego ejecute EXEC para ejecutar el comando en la transacción y finalmente use el comando GET para verificar el valor de mykey y descubra que el valor de mykey sigue siendo 2, lo que significa que el comando en la transacción no se ha ejecutado en absoluto (debido a que mykey se modificó cuando WATCH monitoreó mykey, las transacciones posteriores se cancelaron).
A través del comando WATCH, podemos implementar la función i++ nosotros mismos. El pseudocódigo es el siguiente:
1234567891011
def incr($key): WATCH. $clave $valor = GET $clave si no $valor $valor = 0 $valor = $valor + 1 MULTI SET $clave $valor resultado = EXEC devuelve resultado[0]
Dado que EXEC devuelve un multi- cadena de línea, use el resultado [0] para representar la primera cadena del valor de retorno.
Nota: Dado que el comando WATCH solo cancela la transacción después de que se modifica la clave monitoreada, no hay garantía de que otros clientes no modifiquen el valor monitoreado, por lo que debe reiniciar manualmente el comando EXEC después de que falle. Ejecutar toda la transacción.
La ejecución del comando EXEC cancelará el monitoreo de las claves monitoreadas mediante el comando WATCH. Si no desea ejecutar los comandos en la transacción, también puede usar el comando UNWATCH para cancelar el monitoreo.