我也遇到过同样的问题;我必须更新信用额度,并且必须从 DB 获取修改时间以及信用详细信息。基本上是
在 MYSQL 中同步/原子执行(先更新然后获取)
我尝试了很多选项,找到了一个解决了我的问题的选项。
1) OPTION_1 选择更新
这是保持锁定直到更新(从 GET 到 UPDATE 的同步),但我需要在更新后锁定直到 GET。
2) OPTION_2 存储过程
存储过程不会像redis lua那样同步执行,所以我们还需要同步代码来执行。
3) OPTION_3 交易
我已经使用了如下的 JPA entityManager,认为在提交之前没有人可以更新,并且在提交之前我将获得更新的对象以及修改的时间(来自 DB)。但我没有得到最新的对象。只有提交我得到了最新的。
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 解决了这个问题,所以在更新之前我获得了锁;然后在 GET 之后我释放了锁。
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;
}