priomsrb
priomsrb

Reputation: 2652

Spring : Difference between method with @Transactional(propagation=Propagation.SUPPORTS) vs no @Transactional

What is the difference between method with @Transactional(propagation = Propagation.SUPPORTS) vs having no @Transactional annotation at all?

@Transactional(propagation = Propagation.SUPPORTS)
public void MyMethod()

vs

public void MyMethod()

Wouldn't the one without the annotation also use a transaction if one is already open, otherwise continue without any transaction?

Upvotes: 9

Views: 1753

Answers (3)

badger
badger

Reputation: 3256

There is a small difference. suppose we have two methods a() and b(), and a() is going to call b(). a itself is transnational and its propagation level is Propagation.REQUIRED but b one time is annotated with @Transactional(propagation = Propagation.SUPPORTS) and one time is not with annotation.

case 1:

  @Transactional
  public void a() {
    for (int i = 0; i < 10; i++) {
      try {
        productRepository.b(i, "product " + i);
      } catch (RuntimeException ex){
        // do nothing
      }
    }
  }


  public void b(int id, String name) {
    if(id > 5)
      throw new RuntimeException();
    String sql = "INSERT INTO test_table VALUES(?, ?)";
    template.update(sql, id, name);
  }

in case 1 we have aspect() -> a() -> b() and you are able to prevent RuntimeException to reach aspect and aspect inspects the transaction to see whether it is marked to rollback, so aspect consider this transaction successful and you can see we have this result in our database

0,product 0
1,product 1
2,product 2
3,product 3
4,product 4
5,product 5

even though multiple exceptions were thrown but we were able to commit the operations have been done so far.

now consider case 2:

  @Transactional
  public void a() {
    for (int i = 0; i < 10; i++) {
      try {
        productRepository.b(i, "product " + i);
      } catch (RuntimeException ex){
        // do nothing
      }
    }
  }

  @Transactional(propagation = Propagation.SUPPORTS)
  public void b(int id, String name) {
    if(id > 5)
      throw new RuntimeException();
    String sql = "INSERT INTO test_table VALUES(?, ?)";
    template.update(sql, id, name);
  }

with propagation = Propagation.SUPPORTS if a transaction already exists it's going to use it. so if you throw an exception in b it is going to mark the same transaction to rollback and even if you use the try/catch block to prevent the RuntimeException to reach aspect in a() the transaction is already marked to rollback in b and you see no result in your database. aspect() -> a() -> aspect() -> b()

credit goes to Laurentiu Spilca, see this and read the comment section

Upvotes: 4

Shailesh Chandra
Shailesh Chandra

Reputation: 2340

Yes one without any annotation will use existing transaction if one is already open but what if there is not any won't you want to revert the changes if your transaction fails.

Propagation has also other attribute has well in case you method is not dependant of parent transaction and runs in individual transaction scope, probably you can go for REQUIRES_NEW this way you can have independent transaction for your method.

Upvotes: -1

Ori Marko
Ori Marko

Reputation: 58832

From your link, it states that Propagation.SUPPORTS might have impact on synchronization:

SUPPORTS is slightly different from no transaction at all, as it defines a transaction scope that synchronization will apply for. As a consequence, the same resources (JDBC Connection, Hibernate Session, etc) will be shared for the entire specified scope

Upvotes: 1

Related Questions