30

According to the Spring javadoc @Transactional(propagation = Propagation.SUPPORTS)

Support a current transaction, execute non-transactionally if none exists. Analogous to EJB transaction attribute of the same name.

It seems that I can just declare methods non transactionaly and be just done with it so my questions are.

  • What are some situations where SUPPORTS propagation is needed?
  • What is the point of the Supports propagation?

Can anyone give a real world example / scenario where SUPPORTS was actually useful?

ams
  • 60,316
  • 68
  • 200
  • 288
  • Heva a look at this answer: http://stackoverflow.com/questions/6437828/spring-transactions-with-supports-propagation#6437924 – Grigory Kislin Apr 07 '16 at 12:56

4 Answers4

8

Easiest example I can think of would be a method that sends some content to a JMS server. If you are in the context of a transaction, you want the message to be coupled to the transaction scope. But if there isn't already a transaction running, why bother calling the transaction server also and starting one just to do a one-off message?

Remember these can be declared on an API as well as an implementation. So even if there isn't much difference for your use case between putting it there and putting nothing there, it still adds value for an API author to specify what operations are able to be included in a transaction, as opposed to operations that perhaps call an external system that does not participate in transactions.

This is of course in a JTA context. The feature doesn't really have much practical use in a system where transactions are limited to resource-local physical database transactions.

Affe
  • 47,174
  • 11
  • 83
  • 83
  • in the JMS example you give, if there is no tx but the jms session / producer is shared then the message that is sent as part of the TX. I guess a distributed tx is the only place where SUPPORTS can be useful. – ams Feb 27 '13 at 19:14
  • I think it can still be useful in a non-distributed setting as an API marker if you have instances of NOT_SUPPORTED and want to differentiate. But you're right that implementation wise it's not really much different from putting nothing there at all if tx are not distributed. – Affe Feb 27 '13 at 19:17
  • 1
    I don't see why distributed or not would make any difference. A method without SUPPORTS that has not the NOT_SUPPORTED added, do effectively support transactions. That's like the whole point of all of this. It's like adding a "@PossiblyOverridden" annotation to every non-final method. Pointless! Affe, your first paragraph.. is wrong? "If there is no transaction running" then there is no transaction running. Your second paragraph, also wrong? Again, if I do NOT support transactions I use NOT_SUPPORTED. Anything anywhere that has no transaction annotation effectively "supports". – Martin Andersson Mar 04 '20 at 15:21
  • 1
    I'm not sure what kind of response you're looking for commenting on a 7 year old answer about an 18 year old API that it seems like a silly designed based on modern sensibilities.... Yes.. it effectively "does nothing"... yes Sun Engineers 20 years ago had different design philosophies from google and facebook engineers today? If I were answering the question today I probably would write something like "That's just the way we rolled in 2002, the sort of people who got excited about UML valued 'completeness' like that even though the setting is actually a no-op." – Affe Mar 04 '20 at 16:11
5

It makes a good pair along with the readOnly=true Transactional flag on a select operation especially when ORM is used:

@Transactional(readOnly = true, propagation=Propagation.SUPPORTS)
public Pojo findPojo(long pojoId) throws Exception {
   return em.find(Pojo.class, pojoId);
}

In this case you make sure not to pay to price of creating a new transaction if there isn't one already just for performing a select operation.

Although if you have been in that thought process already you might even consider ditch the Transactional aspect all together:

public Pojo findPojo(long pojoId) throws Exception {
   return em.find(Pojo.class, pojoId);
}
dimitrisli
  • 20,895
  • 12
  • 59
  • 63
  • so...Does it really deserve to put the @Transactional annotation for making selects in a local database through an ORM framework (e.g. MyBatis)? – aloplop85 Jul 11 '13 at 11:09
  • by "ditch the Transactional aspect", is this the same as using @NotTransactional? – John Little Apr 16 '15 at 13:32
  • If something has no transaction aspect, or is @NotTransactional, and it is called from within a transaction, what happens? e.g. if transactional method A writes something to the DB, then calls NotTransactional method be, which also writes something, then eiter A or B throw an unchecked exception, which get rolled back? – John Little Apr 16 '15 at 13:34
  • I still see no difference between having SUPPORTS versus not having it. I think the API designers were simply put it obsessing too much over annotations. Maybe one day in the future we will reverse this evil and go back to doing real object-oriented programming the way God intended. – Martin Andersson Mar 04 '20 at 15:25
0

According this issues Improve performance with Propagation.SUPPORTS for readOnly operation you should not set read-only transaction with Propagation.SUPPORTS:

It's by no means clear that the change would actually improve performance. There's multiple aspects in this. First of them is that the linked article is dated and incredibly flawed as it aggressively simplifies things. I can go into details if you want but I'll leave it at that for now. There are a lot of things playing into execution performance here. Without a transaction in progress neither the readOnly flag is propagated to the JDBC driver (which would cause optimizations for a lot of databases not being applied) nor would you apply the optimizations in Spring's JPA resource management code like explicitly turning off flushing, which - if applied - can dramatically improve performance in case you read a lot of data.

Grigory Kislin
  • 16,647
  • 10
  • 125
  • 197
0

Using Propagation.SUPPORTS you can trigger setting rollback only flag when exception is thrown. For example in the following code although there is a catch block UnexpectedRollbackException will be thrown when leaving txRequired block.

TransactionTemplate txRequired = new TransactionTemplate(platformTransactionManager);
TransactionTemplate txSupports = new TransactionTemplate(platformTransactionManager);
txRequired.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
txSupports.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);

//prints 'Exception handled' and then throws UnexpectedRollbackException
txRequired.executeWithoutResult(tx -> {
    try {
        txSupports.executeWithoutResult(tx2 -> {
            throw new RuntimeException();
        });
    } catch (Exception ex) {
        System.out.println("Exception handled");
    }
}); 

Code below will obviously not throw any exception. The only difference is lack of PROPAGATION_SUPPORTS block.

txRequired.executeWithoutResult((tx) -> {
    try {
        throw new RuntimeException();
    } catch (Exception ex) {
        System.out.println("Exception handled");
    }
});
Sankozi
  • 500
  • 5
  • 22