es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Quiero poner un bloqueo de escritura en una fila de base de datos (PostgreSQL), para evitar que otra transacción (de cualquiera de los nodos) modifique la fila.

Quiero bloquear la escritura en una fila de una base de datos para no permitir que otra transacción la modifique (desde cualquiera de las pods en un entorno con clúster).
Estoy teniendo problemas en un entorno con clúster, donde tenemos 3 pods de aplicación. Intenté usar @Lock(LockModeType.PESSIMISTIC_WRITE) pero no está funcionando.
findById no bloquea la fila y devuelve la misma entidad a todas las instancias

Código de ejemplo:
“`
@Transactional
public boolean updateLicenseCount(String serviceId, String tenantId){
LicenseCountId licenseCountId = new LicenseCountId(tenantId, serviceId);
Optional<LicenseCountEntity> licenseCountEntity = springJpaLicenseCountRepository.findById(licenseCountId);</p>

<pre><code> //Realizar alguna operación en licenseCountEntity
//guardar la licenseCountEntity

}

//Esto es lo que tengo en springJpaLicenseCountRepository
@Lock(LockModeType.PESSIMISTIC_WRITE)
public Optional<LicenseCountEntity> findById(LicenseCountId licenseCountId);
</code></pre>

“`

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Para bloquear en escritura una fila en una base de datos y evitar que otra transacción la modifique en un entorno de clúster, puedes probar el siguiente enfoque:

    1. Usa la anotación @Lock(LockModeType.PESSIMISTIC_WRITE) para aplicar un bloqueo en escritura pesimista a la fila cuando la recuperes de la base de datos.
    2. Asegúrate de marcar el método con @Transactional para garantizar que la transacción se confirme después de que la fila se actualice.
    3. Guarda la entidad actualizada después de realizar las operaciones necesarias en ella.

    Sin embargo, en tu implementación actual, la anotación @Lock no funciona como se esperaba y el método findById no bloquea la fila. Una posible razón para esto podría ser que LockModeType.PESSIMISTIC_WRITE no sea compatible con la base de datos subyacente utilizada en el entorno de clúster.

    Para superar este problema, puedes intentar usar una consulta SQL personalizada para recuperar y bloquear la fila para su actualización. Aquí tienes un ejemplo:

    @Modifying
    @Query(value = "SELECT * FROM LicenseCountEntity WHERE tenant_id = :tenantId AND service_id = :serviceId FOR UPDATE", nativeQuery = true)
    LicenseCountEntity findAndLock(@Param("tenantId") String tenantId, @Param("serviceId") String serviceId);
    

    En este ejemplo, usamos una consulta SQL nativa con la cláusula FOR UPDATE para bloquear la fila para su actualización. La anotación @Modifying se usa para indicar que la consulta modifica la base de datos.

    Después de recuperar y bloquear la fila, puedes realizar las operaciones necesarias en la entidad y guardarla de nuevo en la base de datos.

    @Transactional
    public boolean updateLicenseCount(String serviceId, String tenantId){
      LicenseCountEntity licenseCountEntity = springJpaLicenseCountRepository.findAndLock(tenantId, serviceId);
    
      //Realiza alguna operación en licenseCountEntity
      //Guarda licenseCountEntity
    
      springJpaLicenseCountRepository.save(licenseCountEntity);
    }
    

    Con este enfoque, la fila recuperada está bloqueada para su actualización y no puede ser modificada por otra transacción hasta que se libera el bloqueo.

Comments are closed.