I have faced the same issue; I have to update the credit amount, and have to get modified time, along with credit details from DB. It is basically
SYNCHRONOUSLY/ATOMICALLY perform (UPDATE then GET) in MYSQL
I have tried many options and found one that solved my issue.
1) OPTION_1 SELECT FOR UPDATE
This is maintaining the lock till update (SYNC from GET to UPDATE), but i need lock after update till the GET.
2) OPTION_2 Stored procedure
Stored procedure will not execute synchronously like redis lua, So there also we need sync code to perform that.
3) OPTION_3 Transaction
I have used JPA entityManager like below, thought that before commit no one can update, and before commit i will get the updated object along with modified time (from DB). But i didn't get the latest object. Only commit i got the latest.
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 solved the issue, so before update i acquired the lock; then after GET i have released the lock.
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;
}