Dirty read

Dirty read happens when a transaction reads the data that another transaction has updated but still not committed. For example, two runnable objects can work with the same account entity on two different transactions. The runnable object reads the account object as follows:

@Transactional(value = REQUIRES_NEW)
public class ReadAccount implements Runnable {
@PersistenceContext
private EntityManager entityManager;
...
@Override
public void run() {
...
CountDownLatch latch = new CountDownLatch(1);
latch.await(firstWaitTime, MILLISECONDS);
Account account = entityManager.find(Account.class,
accountNumber);
firstResult = account.getCredit();
latch.await(secondWaitTime, MILLISECONDS);
account = entityManager.find(Account.class, accountNumber);
secondResult = account.getCredit();
...
}
}

Through the REQUIRED_NEW transaction type, we force the thread to start a new transaction during the read operation. We will read the credit of the same account twice. The CountDownLatch provided by the SE concurrent API allows us to wait for an established time, so in the meantime we can start another transaction. This new transaction can execute the write operations provided by the second runnable object:

@Transactional(value = REQUIRES_NEW)
public class WriteAccount implements Runnable {
@PersistenceContext
private EntityManager entityManager;
...
@Override
public void run() {
...
CountdownLatch latch = new CountDownLatch(1);
Account account = entityManager.find(Account.class,
accountNumber);
account.add(amount);
entityManager.merge(account);
latch.await(waitTime, MILLISECONDS);
result = account.getCredit();
...
}

In this object, we will increase the credit of the account. Now, execute the two transactions through the managed executor service:

@Inject
private ReadAccount readAccount;
@Inject
private WriteAccount writeAccount;
...
readAccount.setAccountNumber(123);
readAccount.setFirstWaitTime(1000);
readAccount.setSecondWaitTime(0);
writeAccount.setAccountNumber(123);
writeAccount.setAmount(456.77);
writeAccount.setWaitTime(2000);
defaultExecutor.submit(writeAccount);
defaultExecutor.submit(readAccount);

The operations can be simplified so:

  • The first transaction starts and we have a first read of account 123
  • The second transaction starts and an update of credit of 456.77 is done in account 123
  • The second transaction ends
  • The first transaction ends
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.45.162