Reputation: 2652
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
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
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
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