0

I have a situation, where data has concurrency in transaction.

Example: User 1 create Transaction 1 with Item 1 qty 3 and Item 2 qty 5. User 2 create Transaction 2 with Item 1 qty 6 and Item 2 qty 7.

Every Item has each their own balance (like in warehouse, item in and out).

How can I prevent concurrency that item balance from item 1 and item 2 count correctly, if transaction 1 and transaction 2 run in the same time from diffrence users?

Item 1 should has balance 9 (3 + 6), not 3 or 6, because of overwrite. Item 2 should has balance 12 (5 + 7).

I had experience in ColdFusion. When I used function cftransaction, every sql query will lock data and table (not all table, only in cftransaction) until commit or rollback called (correct me if I misunderstand).

What until now I apply:

In persistence.xml

<property name="eclipselink.session.customizer"
            value="com.sft.FlexiSessionCustomizer" />

In java file:

public class FlexiSessionCustomizer implements SessionCustomizer {

    @Override
    public void customize(Session session) throws Exception {
        DatabaseLogin databaseLogin = (DatabaseLogin) session
              .getDatasourceLogin();
        databaseLogin
              .setTransactionIsolation(DatabaseLogin.TRANSACTION_SERIALIZABLE);
    }

}

Insert method (it's pure insert to database):

public boolean insertDataBean(Object data) {

    if (data == null) {
        logger.error("Data is not valid.");
        return false;
    }

    boolean result = true;

    EntityManager em = this.createEntityManager();

    data.setCreatedDate(new Timestamp((new Date()).getTime()));

    EntityTransaction entr = em.getTransaction();

    try {
        entr.begin();
        em.persist(data);
        entr.commit();

    } catch (Exception e) {
        logger.error("ERROR INSERT : " + data.getClass().getName() + " | "
              + e.getMessage());
        result = false;
    }

    em.close();

    return result;
}

Call the insert method:

insertDataBean(transaction1); // from user 1

insertDataBean(transaction2); // from user 2

Is that enough to prevent concurrency?

What I think, maybe, I should change the insert code like:

public boolean insertDataBean(Object data) {

        if (data == null) {
            logger.error("Data is not valid.");
            return false;
        }

        boolean result = true;

        EntityManager em = this.createEntityManager();

        data.setCreatedDate(new Timestamp((new Date()).getTime()));

        EntityTransaction entr = em.getTransaction();

        try {
            entr.begin();

            // all code, like read item balance and calculation item balance? 
            // should query use the same entity manager (em) or new entity manager will be the same?

            em.persist(data);

            // Other code transaction

            entr.commit();

        } catch (Exception e) {
            logger.error("ERROR INSERT : " + data.getClass().getName() + " | "
                  + e.getMessage());
            result = false;
        }

        em.close();

        return result;
    }

Do I still need to appy Pessimistic-locking?

Maybe someone can help me, to prevent the concurrency in transactions?

Thank you in advance.

Ndrik7
  • 103
  • 13
  • It isn't clear what problem you are trying to prevent or why, nor does your code even show an Item 1 or 2 since you are persisting an entirely new row to the database. If you are trying to delay the persist until after some other transaction has committed, you will have to test to make sure it works with your database settings. But be aware that this level of locking is usually avoided where ever possible for performance reasons. – Chris Feb 25 '19 at 16:47
  • Hi, thank you for the reply. Those are new rows in transactions, but the real case stand on insert (or maybe update) balance of items. – Ndrik7 Feb 25 '19 at 17:04
  • Hi, I edited the question. Maybe it can make clearly. Thank you. – Ndrik7 Feb 25 '19 at 17:11
  • You are still showing a persist call, which is inserting entirely new data, without showing how you are querying or obtaining the data you mention for items 1+2. Yes, you need pessimistic locking if you are going to query over tables/rows and don't want changes to those objects in those queries while your transaction is active - you need to wrap it all in one transaction or only your 'persist' call is transactional. – Chris Feb 26 '19 at 16:29

0 Answers0