Skip to content

Commit cc77b4b

Browse files
committed
Explicit notes on isolation level handling in participating transactions
Issue: SPR-16463 (cherry picked from commit 0ac117f)
1 parent fd964ca commit cc77b4b

File tree

4 files changed

+77
-23
lines changed

4 files changed

+77
-23
lines changed

spring-tx/src/main/java/org/springframework/transaction/TransactionDefinition.java

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -203,21 +203,29 @@ public interface TransactionDefinition {
203203

204204
/**
205205
* Return the isolation level.
206-
* <p>Must return one of the {@code ISOLATION_XXX} constants
207-
* defined on {@link TransactionDefinition this interface}.
208-
* <p>Only makes sense in combination with {@link #PROPAGATION_REQUIRED}
209-
* or {@link #PROPAGATION_REQUIRES_NEW}.
206+
* <p>Must return one of the {@code ISOLATION_XXX} constants defined on
207+
* {@link TransactionDefinition this interface}. Those constants are designed
208+
* to match the values of the same constants on {@link java.sql.Connection}.
209+
* <p>Exclusively designed for use with {@link #PROPAGATION_REQUIRED} or
210+
* {@link #PROPAGATION_REQUIRES_NEW} since it only applies to newly started
211+
* transactions. Consider switching the "validateExistingTransactions" flag to
212+
* "true" on your transaction manager if you'd like isolation level declarations
213+
* to get rejected when participating in an existing transaction with a different
214+
* isolation level.
210215
* <p>Note that a transaction manager that does not support custom isolation levels
211216
* will throw an exception when given any other level than {@link #ISOLATION_DEFAULT}.
212217
* @return the isolation level
218+
* @see #ISOLATION_DEFAULT
219+
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setValidateExistingTransaction
213220
*/
214221
int getIsolationLevel();
215222

216223
/**
217224
* Return the transaction timeout.
218225
* <p>Must return a number of seconds, or {@link #TIMEOUT_DEFAULT}.
219-
* <p>Only makes sense in combination with {@link #PROPAGATION_REQUIRED}
220-
* or {@link #PROPAGATION_REQUIRES_NEW}.
226+
* <p>Exclusively designed for use with {@link #PROPAGATION_REQUIRED} or
227+
* {@link #PROPAGATION_REQUIRES_NEW} since it only applies to newly started
228+
* transactions.
221229
* <p>Note that a transaction manager that does not support timeouts will throw
222230
* an exception when given any other timeout than {@link #TIMEOUT_DEFAULT}.
223231
* @return the transaction timeout
@@ -226,13 +234,12 @@ public interface TransactionDefinition {
226234

227235
/**
228236
* Return whether to optimize as a read-only transaction.
229-
* <p>The read-only flag applies to any transaction context, whether
230-
* backed by an actual resource transaction
231-
* ({@link #PROPAGATION_REQUIRED}/{@link #PROPAGATION_REQUIRES_NEW}) or
232-
* operating non-transactionally at the resource level
233-
* ({@link #PROPAGATION_SUPPORTS}). In the latter case, the flag will
234-
* only apply to managed resources within the application, such as a
235-
* Hibernate {@code Session}.
237+
* <p>The read-only flag applies to any transaction context, whether backed
238+
* by an actual resource transaction ({@link #PROPAGATION_REQUIRED}/
239+
* {@link #PROPAGATION_REQUIRES_NEW}) or operating non-transactionally at
240+
* the resource level ({@link #PROPAGATION_SUPPORTS}). In the latter case,
241+
* the flag will only apply to managed resources within the application,
242+
* such as a Hibernate {@code Session}.
236243
* <p>This just serves as a hint for the actual transaction subsystem;
237244
* it will <i>not necessarily</i> cause failure of write access attempts.
238245
* A transaction manager which cannot interpret the read-only hint will

spring-tx/src/main/java/org/springframework/transaction/annotation/Transactional.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -86,26 +86,38 @@
8686
/**
8787
* The transaction isolation level.
8888
* <p>Defaults to {@link Isolation#DEFAULT}.
89+
* <p>Exclusively designed for use with {@link Propagation#REQUIRED} or
90+
* {@link Propagation#REQUIRES_NEW} since it only applies to newly started
91+
* transactions. Consider switching the "validateExistingTransactions" flag to
92+
* "true" on your transaction manager if you'd like isolation level declarations
93+
* to get rejected when participating in an existing transaction with a different
94+
* isolation level.
8995
* @see org.springframework.transaction.interceptor.TransactionAttribute#getIsolationLevel()
96+
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setValidateExistingTransaction
9097
*/
9198
Isolation isolation() default Isolation.DEFAULT;
9299

93100
/**
94101
* The timeout for this transaction.
95102
* <p>Defaults to the default timeout of the underlying transaction system.
103+
* <p>Exclusively designed for use with {@link Propagation#REQUIRED} or
104+
* {@link Propagation#REQUIRES_NEW} since it only applies to newly started
105+
* transactions.
96106
* @see org.springframework.transaction.interceptor.TransactionAttribute#getTimeout()
97107
*/
98108
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
99109

100110
/**
101-
* {@code true} if the transaction is read-only.
111+
* A boolean flag that can be set to {@code true} if the transaction is
112+
* effectively read-only, allowing for corresponding optimizations at runtime.
102113
* <p>Defaults to {@code false}.
103114
* <p>This just serves as a hint for the actual transaction subsystem;
104115
* it will <i>not necessarily</i> cause failure of write access attempts.
105116
* A transaction manager which cannot interpret the read-only hint will
106117
* <i>not</i> throw an exception when asked for a read-only transaction
107118
* but rather silently ignore the hint.
108119
* @see org.springframework.transaction.interceptor.TransactionAttribute#isReadOnly()
120+
* @see org.springframework.transaction.support.TransactionSynchronizationManager#isCurrentTransactionReadOnly()
109121
*/
110122
boolean readOnly() default false;
111123

spring-tx/src/main/java/org/springframework/transaction/support/AbstractPlatformTransactionManager.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -214,6 +214,7 @@ public final boolean isNestedTransactionAllowed() {
214214
* <p>Default is "false", leniently ignoring inner transaction settings,
215215
* simply overriding them with the outer transaction's characteristics.
216216
* Switch this flag to "true" in order to enforce strict validation.
217+
* @since 2.5.1
217218
*/
218219
public final void setValidateExistingTransaction(boolean validateExistingTransaction) {
219220
this.validateExistingTransaction = validateExistingTransaction;
@@ -222,6 +223,7 @@ public final void setValidateExistingTransaction(boolean validateExistingTransac
222223
/**
223224
* Return whether existing transactions should be validated before participating
224225
* in them.
226+
* @since 2.5.1
225227
*/
226228
public final boolean isValidateExistingTransaction() {
227229
return this.validateExistingTransaction;
@@ -284,6 +286,7 @@ public final boolean isGlobalRollbackOnParticipationFailure() {
284286
* boundary. This allows, for example, to continue unit tests even after an
285287
* operation failed and the transaction will never be completed. All transaction
286288
* managers will only fail earlier if this flag has explicitly been set to "true".
289+
* @since 2.0
287290
* @see org.springframework.transaction.UnexpectedRollbackException
288291
*/
289292
public final void setFailEarlyOnGlobalRollbackOnly(boolean failEarlyOnGlobalRollbackOnly) {
@@ -293,6 +296,7 @@ public final void setFailEarlyOnGlobalRollbackOnly(boolean failEarlyOnGlobalRoll
293296
/**
294297
* Return whether to fail early in case of the transaction being globally marked
295298
* as rollback-only.
299+
* @since 2.0
296300
*/
297301
public final boolean isFailEarlyOnGlobalRollbackOnly() {
298302
return this.failEarlyOnGlobalRollbackOnly;

spring-tx/src/main/java/org/springframework/transaction/support/DefaultTransactionDefinition.java

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -108,7 +108,7 @@ public DefaultTransactionDefinition(int propagationBehavior) {
108108
* Set the propagation behavior by the name of the corresponding constant in
109109
* TransactionDefinition, e.g. "PROPAGATION_REQUIRED".
110110
* @param constantName name of the constant
111-
* @exception IllegalArgumentException if the supplied value is not resolvable
111+
* @throws IllegalArgumentException if the supplied value is not resolvable
112112
* to one of the {@code PROPAGATION_} constants or is {@code null}
113113
* @see #setPropagationBehavior
114114
* @see #PROPAGATION_REQUIRED
@@ -123,8 +123,16 @@ public final void setPropagationBehaviorName(String constantName) throws Illegal
123123
/**
124124
* Set the propagation behavior. Must be one of the propagation constants
125125
* in the TransactionDefinition interface. Default is PROPAGATION_REQUIRED.
126-
* @exception IllegalArgumentException if the supplied value is not
127-
* one of the {@code PROPAGATION_} constants
126+
* <p>Exclusively designed for use with {@link #PROPAGATION_REQUIRED} or
127+
* {@link #PROPAGATION_REQUIRES_NEW} since it only applies to newly started
128+
* transactions. Consider switching the "validateExistingTransactions" flag to
129+
* "true" on your transaction manager if you'd like isolation level declarations
130+
* to get rejected when participating in an existing transaction with a different
131+
* isolation level.
132+
* <p>Note that a transaction manager that does not support custom isolation levels
133+
* will throw an exception when given any other level than {@link #ISOLATION_DEFAULT}.
134+
* @throws IllegalArgumentException if the supplied value is not one of the
135+
* {@code PROPAGATION_} constants
128136
* @see #PROPAGATION_REQUIRED
129137
*/
130138
public final void setPropagationBehavior(int propagationBehavior) {
@@ -143,7 +151,7 @@ public final int getPropagationBehavior() {
143151
* Set the isolation level by the name of the corresponding constant in
144152
* TransactionDefinition, e.g. "ISOLATION_DEFAULT".
145153
* @param constantName name of the constant
146-
* @exception IllegalArgumentException if the supplied value is not resolvable
154+
* @throws IllegalArgumentException if the supplied value is not resolvable
147155
* to one of the {@code ISOLATION_} constants or is {@code null}
148156
* @see #setIsolationLevel
149157
* @see #ISOLATION_DEFAULT
@@ -158,8 +166,16 @@ public final void setIsolationLevelName(String constantName) throws IllegalArgum
158166
/**
159167
* Set the isolation level. Must be one of the isolation constants
160168
* in the TransactionDefinition interface. Default is ISOLATION_DEFAULT.
161-
* @exception IllegalArgumentException if the supplied value is not
162-
* one of the {@code ISOLATION_} constants
169+
* <p>Exclusively designed for use with {@link #PROPAGATION_REQUIRED} or
170+
* {@link #PROPAGATION_REQUIRES_NEW} since it only applies to newly started
171+
* transactions. Consider switching the "validateExistingTransactions" flag to
172+
* "true" on your transaction manager if you'd like isolation level declarations
173+
* to get rejected when participating in an existing transaction with a different
174+
* isolation level.
175+
* <p>Note that a transaction manager that does not support custom isolation levels
176+
* will throw an exception when given any other level than {@link #ISOLATION_DEFAULT}.
177+
* @throws IllegalArgumentException if the supplied value is not one of the
178+
* {@code ISOLATION_} constants
163179
* @see #ISOLATION_DEFAULT
164180
*/
165181
public final void setIsolationLevel(int isolationLevel) {
@@ -177,6 +193,11 @@ public final int getIsolationLevel() {
177193
/**
178194
* Set the timeout to apply, as number of seconds.
179195
* Default is TIMEOUT_DEFAULT (-1).
196+
* <p>Exclusively designed for use with {@link #PROPAGATION_REQUIRED} or
197+
* {@link #PROPAGATION_REQUIRES_NEW} since it only applies to newly started
198+
* transactions.
199+
* <p>Note that a transaction manager that does not support timeouts will throw
200+
* an exception when given any other timeout than {@link #TIMEOUT_DEFAULT}.
180201
* @see #TIMEOUT_DEFAULT
181202
*/
182203
public final void setTimeout(int timeout) {
@@ -194,6 +215,16 @@ public final int getTimeout() {
194215
/**
195216
* Set whether to optimize as read-only transaction.
196217
* Default is "false".
218+
* <p>The read-only flag applies to any transaction context, whether backed
219+
* by an actual resource transaction ({@link #PROPAGATION_REQUIRED}/
220+
* {@link #PROPAGATION_REQUIRES_NEW}) or operating non-transactionally at
221+
* the resource level ({@link #PROPAGATION_SUPPORTS}). In the latter case,
222+
* the flag will only apply to managed resources within the application,
223+
* such as a Hibernate {@code Session}.
224+
* <p>This just serves as a hint for the actual transaction subsystem;
225+
* it will <i>not necessarily</i> cause failure of write access attempts.
226+
* A transaction manager which cannot interpret the read-only hint will
227+
* <i>not</i> throw an exception when asked for a read-only transaction.
197228
*/
198229
public final void setReadOnly(boolean readOnly) {
199230
this.readOnly = readOnly;

0 commit comments

Comments
 (0)