Ich bin mit dem gleichen Problem konfrontiert; ich muss den Kreditbetrag aktualisieren und die geänderte Zeit zusammen mit den Kreditdetails aus der DB abrufen. Es ist im Grunde
SYNCHRONOUS/ATOMICALLY durchführen (UPDATE dann GET) in MYSQL
Ich habe viele Optionen ausprobiert und eine gefunden, die mein Problem gelöst hat.
1) OPTION_1 ZUR AKTUALISIERUNG AUSWÄHLEN
Dies ist die Aufrechterhaltung der Sperre bis Update (SYNC von GET zu UPDATE), aber ich brauche Sperre nach Update bis die GET.
2) OPTION_2 Gespeicherte Prozedur
Gespeicherte Prozedur wird nicht synchron wie Redis Lua ausgeführt, so dass auch wir Sync-Code benötigen, um das durchzuführen.
3) OPTION_3 Transaktion
Ich habe JPA entityManager wie unten verwendet, dachte, dass vor Commit niemand aktualisieren kann, und vor Commit werde ich das aktualisierte Objekt zusammen mit geänderten Zeit (von DB) erhalten. Aber ich habe nicht das neueste Objekt erhalten. Nur Commit habe ich die neuesten.
try {
entityManager.getTransaction().begin();
//entityManager.persist(object);
int upsert = entityManager.createNativeQuery(
"update com.bill.Credit c set c.balance = c.balance - ?1
where c.accountId = ?2 and c.balance >= ?1").executeUpdate();
//c.balance >= ? for limit check
Credit newCredit = entityManager.find(Credit.class, "id");
entityManager.refresh(newCredit); //SHOULD GET LATEST BUT NOT
entityManager.getTransaction().commit();
} finally {
entityManager.unwrap(Session.class).close();
}
4) OPTION_4 LOCK hat das Problem gelöst, d.h. vor der Aktualisierung habe ich die Sperre erworben; nach GET habe ich die Sperre wieder freigegeben.
private Object getLock(final EntityManager entityManager, final String Id){
entityManager.getTransaction().begin();
Object obj_acquire = entityManager.createNativeQuery("SELECT GET_LOCK('" + Id + "', 10)").getSingleResult();
entityManager.getTransaction().commit();
return obj_acquire;
}
private Object releaseLock(final EntityManager entityManager, final String Id){
entityManager.getTransaction().begin();
Object obj_release = entityManager.createNativeQuery("SELECT RELEASE_LOCK('" + Id + "')").getSingleResult();
entityManager.getTransaction().commit();
return obj_release;
}
1 Stimmen
Ich denke, das ist bisher die beste Lösung stackoverflow.com/questions/22066397/