Spring: propagating transactions
I have the following code:
@Transactional
public void handle() {
for (Item item : getItems()) {
handle(item);
}
}
@Transactional(propagation = Propagation.NESTED)
public void handle(Item item) {
/* logic here */
}
Let's say that the loop in is handle()
processing 10 items. Also suppose it handle(Item)
throws an exception for 3 items .
My questions:
[1] Will the external transaction be executed after the 10th item? Does this mean that the necessary changes will be made for 7 items and that any intermediate changes for 3 other items will be pushed back to the created savepoint?
[2] Will an exception handle(Item)
be caught and not sent to handle()
? Is this done with @Transactional
?
[3] Also, I would like to understand what is the difference in behavior with the following stream:
@Transactional
public void handle() {
for (Item item : getItems()) {
handle(item);
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void handle(Item item) {
/* logic here */
}
From my understanding from the docs, a new transaction will be started here and the active transaction will be suspended. This is different from NESTED
when a savepoint is created and the current transaction is still in use. But I believe that REQUIRES_NEW
changes for 7 items will be made here as well and that any intermediate changes for the other 3 items will be forgotten.
So what's the real difference then (if any)?
source to share
NESTED starts the main subtransaction. REQUIRES_NEW starts a separate transaction.
If you mark the REQUIRES_NEW method after the method exit data remains in the DB (committed by a separate transaction) no matter what happens to the outer transaction.
In the case of NESTED, the changes are discarded if the outer transaction is canceled.
See answers here
source to share
From my understanding from the docs, there will be a new transaction here and the active transaction will be suspended.
- if the handle () method and the handle (element element) are inside the same service, only one transaction will be started - for the first method. He called self-exclusion. cm.:
A Spring Hard Fact About Transaction Management And WHAT IS AN OPERATION? ...
to apply a transaction for a descriptor (Item) inside a descriptor () you must
@Transactional
public void handle() {
for (Item item : getItems()) {
applicationContext.getBean(your service).handle(item);
}
}
or use spring aspectj load time weaving for self-invocation (inside one service call one method from another)
Calling the propagated .REQUIRES_NEW method inside the loop is bad for performance, you create a new transaction for each call. You can wrap inside one method, but with exception handling - only for business logic exception! not all types of exceptions
@Transactional
public void handle() {
..some logic
//if you really need it
applicationContext.getBean(your service).handleBatch(getItems());
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void handleBatch(Collection items) {
for (Item item : items) {
applicationContext.getBean(your service).handle(item)
}
}
public void handle(Item item) {
try{
//do operation
}catch(.appropriate type..Exception ex){
//log exception!!!
}
}
- about rollback: Spring does rollback on RuntimeException and Error, but not on checked exceptions. if the method has thrown any checked exception, the changes will be committed. avoid using
@Transactional (rollbackFor = CheckedException.class)
source to share