diff --git a/spring-tx/src/main/java/org/springframework/transaction/annotation/Transactional.java b/spring-tx/src/main/java/org/springframework/transaction/annotation/Transactional.java index 3b26813b253..024e376adaf 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/annotation/Transactional.java +++ b/spring-tx/src/main/java/org/springframework/transaction/annotation/Transactional.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,7 +36,8 @@ import org.springframework.transaction.TransactionDefinition; * does not have to know about annotations. If no rules are relevant to the exception, * it will be treated like * {@link org.springframework.transaction.interceptor.DefaultTransactionAttribute} - * (rolling back on runtime exceptions). + * (rolling back on {@link RuntimeException} and {@link Error} but not on checked + * exceptions). * *

For specific information about the semantics of this annotation's attributes, * consult the {@link org.springframework.transaction.TransactionDefinition} and @@ -102,7 +103,8 @@ public @interface Transactional { *

This just serves as a hint for the actual transaction subsystem; * it will not necessarily cause failure of write access attempts. * A transaction manager which cannot interpret the read-only hint will - * not throw an exception when asked for a read-only transaction. + * not throw an exception when asked for a read-only transaction + * but rather silently ignore the hint. * @see org.springframework.transaction.interceptor.TransactionAttribute#isReadOnly() */ boolean readOnly() default false; @@ -111,10 +113,15 @@ public @interface Transactional { * Defines zero (0) or more exception {@link Class classes}, which must be * subclasses of {@link Throwable}, indicating which exception types must cause * a transaction rollback. + *

By default, a transaction will be rolling back on {@link RuntimeException} + * and {@link Error} but not on checked exceptions (business exceptions). See + * {@link org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)} + * for a detailed explanation. *

This is the preferred way to construct a rollback rule (in contrast to * {@link #rollbackForClassName}), matching the exception class and its subclasses. - *

Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(Class clazz)} + *

Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(Class clazz)}. * @see #rollbackForClassName + * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable) */ Class[] rollbackFor() default {}; @@ -124,7 +131,7 @@ public @interface Transactional { * a transaction rollback. *

This can be a substring of a fully qualified class name, with no wildcard * support at present. For example, a value of {@code "ServletException"} would - * match {@link javax.servlet.ServletException} and its subclasses. + * match {@code javax.servlet.ServletException} and its subclasses. *

NB: Consider carefully how specific the pattern is and whether * to include package information (which isn't mandatory). For example, * {@code "Exception"} will match nearly anything and will probably hide other @@ -132,8 +139,9 @@ public @interface Transactional { * were meant to define a rule for all checked exceptions. With more unusual * {@link Exception} names such as {@code "BaseBusinessException"} there is no * need to use a FQN. - *

Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(String exceptionName)} + *

Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(String exceptionName)}. * @see #rollbackFor + * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable) */ String[] rollbackForClassName() default {}; @@ -144,8 +152,9 @@ public @interface Transactional { *

This is the preferred way to construct a rollback rule (in contrast * to {@link #noRollbackForClassName}), matching the exception class and * its subclasses. - *

Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(Class clazz)} + *

Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(Class clazz)}. * @see #noRollbackForClassName + * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable) */ Class[] noRollbackFor() default {}; @@ -155,8 +164,9 @@ public @interface Transactional { * cause a transaction rollback. *

See the description of {@link #rollbackForClassName} for further * information on how the specified names are treated. - *

Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(String exceptionName)} + *

Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(String exceptionName)}. * @see #noRollbackFor + * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable) */ String[] noRollbackForClassName() default {}; diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/DefaultTransactionAttribute.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/DefaultTransactionAttribute.java index 83de312a258..fc45334c035 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/DefaultTransactionAttribute.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/DefaultTransactionAttribute.java @@ -111,9 +111,18 @@ public class DefaultTransactionAttribute extends DefaultTransactionDefinition im } /** - * The default behavior is as with EJB: rollback on unchecked exception. - * Additionally attempt to rollback on Error. - *

This is consistent with TransactionTemplate's default behavior. + * The default behavior is as with EJB: rollback on unchecked exception + * ({@link RuntimeException}), assuming an unexpected outcome outside of any + * business rules. Additionally, we also attempt to rollback on {@link Error} which + * is clearly an unexpected outcome as well. By contrast, a checked exception is + * considered a business exception and therefore a regular expected outcome of the + * transactional business method, i.e. a kind of alternative return value which + * still allows for regular completion of resource operations. + *

This is largely consistent with TransactionTemplate's default behavior, + * except that TransactionTemplate also rolls back on undeclared checked exceptions + * (a corner case). For declarative transactions, we expect checked exceptions to be + * intentionally declared as business exceptions, leading to a commit by default. + * @see org.springframework.transaction.support.TransactionTemplate#execute */ @Override public boolean rollbackOn(Throwable ex) {