Reputation: 1651
I have a service which runs every few seconds and processes some records from a queue which is stored in the database. I noticed that a @Transactional attribute added and was trying to figure out what it's usage is and wanted to make sure it's the right usage.
@Scheduled(initialDelay = 10000, fixedDelay = 10000)
@Transactional
public void notificationTask() {
Integer txId = myDao.getMinTxIdByStatusCode("Pending");
myDao.updateStatusByTxId(txId, "Processing");
boolean status = true;
Transaction tx = myDao.getTxById(txId);
if (txId != null) {
status = myService.processTx(txId, myTx.getX(), myTx.getY());
if (status) {
myDao.updateStatusByTxId(txId, "Complete");
} else {
myDao.updateStatusByTxId(txId, "Failed");
}
}
}
My main question here is, if for some reason either the getTxById or the processTx methods fail, does that mean with the @Transational attribute, it will roll back the updateStatusByTxId? What is a use case where the Transactional attribute would be used here?
Upvotes: 1
Views: 1780
Reputation: 1874
When you use @Transactional
on a method, Spring wraps the entire method in a transaction. This means that a new transaction is started before the method is entered and committed after the method is exited.
If there is an exception, the whole transaction will be rolled back. That's what is called "atomicity": transactions are "all or nothing".
Thus, @Transactional
is a "shortcut" for something like this when using Hibernate:
@Scheduled(initialDelay = 10000, fixedDelay = 10000)
public void notificationTask() {
Transaction transaction = null;
try {
Session session = sessionFactory.openSession(); //Hibernte session
transaction = session.beginTransaction();
//... your stuff
Integer txId = myDao.getMinTxIdByStatusCode("Pending");
myDao.updateStatusByTxId(txId, "Processing");
boolean status = true;
Transaction tx = myDao.getTxById(txId);
if (txId != null) {
status = myService.processTx(txId, myTx.getX(), myTx.getY());
if (status) {
myDao.updateStatusByTxId(txId, "Complete");
} else {
myDao.updateStatusByTxId(txId, "Failed");
}
}
//... your stuff done
transaction.commit();
}catch (Exception ex) {
ex.printStackTrace();
transaction.rollback();
}
}
So, if your method updateStatusByTxId
is just a database call (is not flushing, nor committing or has is own nested transaction): yes, it is rolled back.
And since the transaction is also active, when entering processTx
, this service call will also be in the same transaction, even if you add an additional @Transactional
to processTx
. Except you explicitly start a new transaction by e.g. @Transactional(Transactional.TxType.REQUIRES_NEW)
.
Additionally, Spring has a really detailed doc: https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#transaction
Upvotes: 1