Cómo prevenir que la base de datos contenga datos antiguos no actualizados previos.
Estoy tratando de trabajar con postgresQL con graphql en un servidor express.
El problema al que me enfrento es que quiero actualizar el valor de la base de datos cuando el usuario llame a la API en el cliente. Cuando se llama dos veces en poco tiempo, dado que el dinero del usuario y la cantidad del producto aún no se han actualizado, ambas funciones obtendrán el mismo dinero, se ejecutarán y la cantidad del producto y el dinero del usuario serán negativos, lo cual no es correcto.
¿Cuál es una forma sencilla de implementar la función de bloqueo para que los datos del usuario específico y los datos del producto no puedan ser accedidos y modificados hasta que el proceso anterior esté terminado, de modo que sea seguro en el hilo de ejecución?
Editar: Sé que puedo agregar un bloqueo en la caché local, pero me gustaría preguntar cuál es el método de manejo típico. ¿Debería simplemente devolver que el proceso está en ejecución cuando está bloqueado? ¿O debería crear un bucle para esperar hasta que se haya completado la primera solicitud? Y si hay algún buen ejemplo de código que pueda seguir.
@Mutation(() => Boolean)
async pay(@Arg(‘amount’) amount: number) {
let userId = 1
let proeductId = 1
const user = await User.findOne(userId); // user = {userId: 1, money: 50}
const product = await Product.findOne(userId); // product= {userId:1, quantity: 1, price: 50}
await new Promise(resolve => setTimeout(resolve, 3000)) // algo de lógica
if(user && product && user?.money >= product.price && product.quantity > 0){
await getConnection().getRepository(User).decrement({ userId }, ‘money’, 50);
await getConnection().getRepository(product).decrement({ userId }, ‘quantity’, 1);
}
}
davy.ai
Para garantizar la seguridad de hilos y el bloqueo para la fila de datos del usuario específico y la fila de datos del producto en una base de datos PostgreSQL con GraphQL en un servidor Express, puede usar las funciones de bloqueo de asesoramiento de PostgreSQL.
Cuando un usuario llama a la API de pago, puede obtener un bloqueo en las filas de datos del usuario y del producto utilizando un bloqueo de asesoramiento con las ID del usuario y del producto como argumentos. El bloqueo se puede liberar una vez que se completa la ejecución de la API.
Una implementación simple de la función de bloqueo se puede hacer de la siguiente manera:
En este ejemplo, la función
acquireAdvisoryLock
intenta obtener el bloqueo de asesoramiento para ellockId
dado. Esto se hace con un bucle que espera entre los intentos de adquirir el bloqueo. Una vez que se obtiene el bloqueo, se devuelve.La función
releaseAdvisoryLock
simplemente libera el bloqueo de asesoramiento para ellockId
dado.En la función
pay
, los bloqueos de asesoramiento se obtienen antes de acceder a las filas de datos del usuario y del producto. Si la ejecución de la API se llama dos veces en un corto período de tiempo, la segunda llamada tendrá que esperar a que se liberen los primeros bloqueos de asesoramiento antes de continuar.Tenga en cuenta que los bloqueos de asesoramiento son bloqueos a nivel de sesión, lo que significa que solo afectan a la sesión de conexión actual de la base de datos. Otras conexiones de base de datos aún pueden acceder a las filas de datos bloqueadas. Sin embargo, en la mayoría de los casos, los bloqueos a nivel de sesión son suficientes para garantizar la seguridad de hilos y prevenir condiciones de carrera.