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)?

+3


source to share


2 answers


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

+1


source


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

      

  1. 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)

+1


source







All Articles