Is there a way to SELECT and UPDATE rows at the same time?

后端 未结 9 1533
醉话见心
醉话见心 2020-12-12 21:01

I\'d like to update a set of rows based on a simple criteria and get the list of PKs that were changed. I thought I could just do something like this but am worried about po

9条回答
  •  旧巷少年郎
    2020-12-12 21:08

    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;
    }
    

提交回复
热议问题