Sé libre de compartir nuestra web y códigos con otro, necesitamos tu ayuda para aumentar esta comunidad.
Solución:
@Lock
es compatible con los métodos CRUD a partir de la versión 1.6 de Spring Data JPA (de hecho, ya hay un hito disponible). Ver este boleto para más detalles.
Con esa versión simplemente declaras lo siguiente:
interface WidgetRepository extends Repository
@Lock(LockModeType.PESSIMISTIC_WRITE)
Widget findOne(Long id);
Esto hará que la parte de implementación de CRUD del proxy del repositorio de respaldo aplique el configurado LockModeType
al find(…)
llamar a la EntityManager
.
Si no desea anular el estándar findOne()
método, puede adquirir un bloqueo en su método personalizado utilizando select ... for update
consulta así:
/**
* Repository for Wallet.
*/
public interface WalletRepository extends CrudRepository, JpaSpecificationExecutor
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("select w from Wallet w where w.id = :id")
Wallet findOneForUpdate(@Param("id") Long id);
Sin embargo, si está utilizando PostgreSQL, las cosas pueden complicarse un poco cuando desea configurar el tiempo de espera de bloqueo para evitar interbloqueos. PostgreSQL ignora la propiedad estándar javax.persistence.lock.timeout
establecido en propiedades JPA o en @QueryHint
anotación.
La única forma en que podía hacerlo funcionar era crear un repositorio personalizado y configurar el tiempo de espera manualmente antes de bloquear una entidad. No es agradable, pero al menos funciona:
public class WalletRepositoryImpl implements WalletRepositoryCustom
@PersistenceContext
private EntityManager em;
@Override
public Wallet findOneForUpdate(Long id)
// explicitly set lock timeout (necessary in PostgreSQL)
em.createNativeQuery("set local lock_timeout to '2s';").executeUpdate();
Wallet wallet = em.find(Wallet.class, id);
if (wallet != null)
em.lock(wallet, LockModeType.PESSIMISTIC_WRITE);
return wallet;
Si puede usar Spring Data 1.6 o superior, ignore esta respuesta y consulte la respuesta de Oliver.
El pesimista Spring Data @Lock
las anotaciones solo se aplican (como usted señaló) a las consultas. No hay anotaciones que yo sepa que puedan afectar una transacción completa. Puede crear un findByOnePessimistic
método que llama findByOne
con un candado pesimista o puedes cambiar findByOne
para obtener siempre un bloqueo pesimista.
Si quisiera implementar su propia solución, probablemente podría hacerlo. Debajo del capó el @Lock
la anotación es procesada por LockModePopulatingMethodIntercceptor
que hace lo siguiente:
TransactionSynchronizationManager.bindResource(method, lockMode == null ? NULL : lockMode);
Podrías crear algunos static administrador de bloqueo que tenía un ThreadLocal
variable miembro y luego tener un aspecto envuelto alrededor de cada método en cada repositorio que llamó bindResource
con el modo de bloqueo establecido en el ThreadLocal
. Esto le permitiría configurar el modo de bloqueo por subproceso. A continuación, podría crear su propia @MethodLockMode
anotación que envolvería el método en un aspecto que establece el modo de bloqueo específico del subproceso antes de ejecutar el método y lo borra después de ejecutar el método.