001package io.ebean; 002 003import io.ebean.annotation.PersistBatch; 004import io.ebean.annotation.TxIsolation; 005import io.ebean.annotation.TxOption; 006import io.ebean.annotation.TxType; 007 008import java.util.ArrayList; 009import java.util.concurrent.Callable; 010 011/** 012 * Holds the definition of how a transactional method should run. 013 * <p> 014 * This information matches the features of the Transactional annotation. You 015 * can use it directly with Runnable or Callable via 016 * {@link DB#execute(TxScope, Runnable)} or 017 * {@link DB#executeCall(TxScope, Callable)}. 018 * </p> 019 * <p> 020 * This object is used internally with the enhancement of a method with 021 * Transactional annotation. 022 * </p> 023 * 024 * @see DB#execute(TxScope, Runnable) 025 * @see DB#executeCall(TxScope, Callable) 026 */ 027public final class TxScope { 028 029 private int profileId; 030 031 private TxType type; 032 033 private String serverName; 034 035 private TxIsolation isolation; 036 037 private TxOption autoPersistUpdates; 038 039 private PersistBatch batch; 040 041 private PersistBatch batchOnCascade; 042 043 private int batchSize; 044 045 private boolean skipGeneratedKeys; 046 047 private boolean readOnly; 048 049 /** 050 * Set this to false if the JDBC batch should not be automatically be flushed when a query is executed. 051 */ 052 private boolean flushOnQuery = true; 053 054 private boolean skipCache; 055 056 private String label; 057 058 private ArrayList<Class<? extends Throwable>> rollbackFor; 059 060 private ArrayList<Class<? extends Throwable>> noRollbackFor; 061 062 private ProfileLocation profileLocation; 063 064 /** 065 * Helper method to create a TxScope with REQUIRES. 066 */ 067 public static TxScope required() { 068 return new TxScope(TxType.REQUIRED); 069 } 070 071 /** 072 * Helper method to create a TxScope with REQUIRES_NEW. 073 */ 074 public static TxScope requiresNew() { 075 return new TxScope(TxType.REQUIRES_NEW); 076 } 077 078 /** 079 * Helper method to create a TxScope with MANDATORY. 080 */ 081 public static TxScope mandatory() { 082 return new TxScope(TxType.MANDATORY); 083 } 084 085 /** 086 * Helper method to create a TxScope with SUPPORTS. 087 */ 088 public static TxScope supports() { 089 return new TxScope(TxType.SUPPORTS); 090 } 091 092 /** 093 * Helper method to create a TxScope with NOT_SUPPORTED. 094 */ 095 public static TxScope notSupported() { 096 return new TxScope(TxType.NOT_SUPPORTED); 097 } 098 099 /** 100 * Helper method to create a TxScope with NEVER. 101 */ 102 public static TxScope never() { 103 return new TxScope(TxType.NEVER); 104 } 105 106 /** 107 * Create a REQUIRED transaction scope. 108 */ 109 public TxScope() { 110 this.type = TxType.REQUIRED; 111 } 112 113 /** 114 * Create with a given transaction scope type. 115 */ 116 public TxScope(TxType type) { 117 this.type = type; 118 } 119 120 /** 121 * Describes this TxScope instance. 122 */ 123 @Override 124 public String toString() { 125 return "TxScope[" + type + "] readOnly[" + readOnly + "] isolation[" + isolation 126 + "] serverName[" + serverName + "] rollbackFor[" + rollbackFor + "] noRollbackFor[" + noRollbackFor + "]"; 127 } 128 129 /** 130 * Return the AutoPersistUpdates mode as a nullable Boolean. 131 */ 132 public Boolean getAutoPersistUpdates() { 133 return autoPersistUpdates == null ? null : autoPersistUpdates.asBoolean(); 134 } 135 136 /** 137 * Return true if PersistBatch has been set. 138 */ 139 public boolean isBatchSet() { 140 return batch != null && batch != PersistBatch.INHERIT; 141 } 142 143 /** 144 * Return true if batch on cascade has been set. 145 */ 146 public boolean isBatchOnCascadeSet() { 147 return batchOnCascade != null && batchOnCascade != PersistBatch.INHERIT; 148 } 149 150 /** 151 * Return true if batch size has been set. 152 */ 153 public boolean isBatchSizeSet() { 154 return batchSize > 0; 155 } 156 157 /** 158 * Check for batchSize being set without batch mode and use this to imply PersistBatch.ALL. 159 */ 160 public void checkBatchMode() { 161 if (batchSize > 0 && notSet(batch) && notSet(batchOnCascade)) { 162 // Use setting the batchSize as implying PersistBatch.ALL for @Transactional 163 batch = PersistBatch.ALL; 164 } 165 } 166 167 /** 168 * Return true if the mode is considered not set. 169 */ 170 private boolean notSet(PersistBatch batchMode) { 171 return batchMode == null || batchMode == PersistBatch.INHERIT; 172 } 173 174 /** 175 * Return the transaction type. 176 */ 177 public TxType getType() { 178 return type; 179 } 180 181 /** 182 * Set the transaction type. 183 */ 184 public TxScope setType(TxType type) { 185 this.type = type; 186 return this; 187 } 188 189 /** 190 * Set the autoPersistUpdates mode. 191 */ 192 public TxScope setAutoPersistUpdates(TxOption autoPersistUpdates) { 193 this.autoPersistUpdates = autoPersistUpdates; 194 return this; 195 } 196 197 /** 198 * Return the transaction profile id. 199 */ 200 public int getProfileId() { 201 return profileId; 202 } 203 204 /** 205 * Set the transaction profile id. 206 */ 207 public TxScope setProfileId(int profileId) { 208 this.profileId = profileId; 209 return this; 210 } 211 212 /** 213 * Return the profile location. 214 */ 215 public ProfileLocation getProfileLocation() { 216 return profileLocation; 217 } 218 219 /** 220 * Set the profile location. 221 */ 222 public TxScope setProfileLocation(ProfileLocation profileLocation) { 223 this.profileLocation = profileLocation; 224 return this; 225 } 226 227 /** 228 * Return true if the L2 cache should be skipped for this transaction. 229 */ 230 public boolean isSkipCache() { 231 return skipCache; 232 } 233 234 /** 235 * Set to true if the transaction should skip L2 cache access. 236 */ 237 public TxScope setSkipCache(boolean skipCache) { 238 this.skipCache = skipCache; 239 return this; 240 } 241 242 /** 243 * Return the label for the transaction. 244 */ 245 public String getLabel() { 246 return label; 247 } 248 249 /** 250 * Set a label for the transaction. 251 */ 252 public TxScope setLabel(String label) { 253 this.label = label; 254 return this; 255 } 256 257 /** 258 * Return the batch mode. 259 */ 260 public PersistBatch getBatch() { 261 return batch; 262 } 263 264 /** 265 * Set the batch mode to use. 266 */ 267 public TxScope setBatch(PersistBatch batch) { 268 this.batch = batch; 269 return this; 270 } 271 272 /** 273 * Return the batch on cascade mode. 274 */ 275 public PersistBatch getBatchOnCascade() { 276 return batchOnCascade; 277 } 278 279 /** 280 * Set the batch on cascade mode. 281 */ 282 public TxScope setBatchOnCascade(PersistBatch batchOnCascade) { 283 this.batchOnCascade = batchOnCascade; 284 return this; 285 } 286 287 /** 288 * Return the batch size. 0 means use the default value. 289 */ 290 public int getBatchSize() { 291 return batchSize; 292 } 293 294 /** 295 * Set the batch size to use. 296 */ 297 public TxScope setBatchSize(int batchSize) { 298 this.batchSize = batchSize; 299 return this; 300 } 301 302 /** 303 * Set if the transaction should skip reading generated keys for inserts. 304 */ 305 public TxScope setSkipGeneratedKeys() { 306 this.skipGeneratedKeys = true; 307 return this; 308 } 309 310 /** 311 * Return true if getGeneratedKeys should be skipped for this transaction. 312 */ 313 public boolean isSkipGeneratedKeys() { 314 return skipGeneratedKeys; 315 } 316 317 /** 318 * Return if the transaction should be treated as read only. 319 */ 320 public boolean isReadonly() { 321 return readOnly; 322 } 323 324 /** 325 * Set if the transaction should be treated as read only. 326 */ 327 public TxScope setReadOnly(boolean readOnly) { 328 this.readOnly = readOnly; 329 return this; 330 } 331 332 /** 333 * Return false if the JDBC batch buffer should not be flushed automatically when a query is executed. 334 */ 335 public boolean isFlushOnQuery() { 336 return flushOnQuery; 337 } 338 339 /** 340 * Set flushOnQuery to be false to stop automatically flushing the JDBC batch buffer when a query is executed. 341 */ 342 public TxScope setFlushOnQuery(boolean flushOnQuery) { 343 this.flushOnQuery = flushOnQuery; 344 return this; 345 } 346 347 /** 348 * Return the isolation level. 349 */ 350 public int getIsolationLevel() { 351 return isolation != null ? isolation.getLevel() : -1; 352 } 353 354 /** 355 * Return the Isolation level this transaction should run with. 356 */ 357 public TxIsolation getIsolation() { 358 return isolation; 359 } 360 361 /** 362 * Set the transaction isolation level this transaction should run with. 363 */ 364 public TxScope setIsolation(TxIsolation isolation) { 365 this.isolation = isolation; 366 return this; 367 } 368 369 /** 370 * Return the serverName for this transaction. If this is null then the 371 * default server (default DataSource) will be used. 372 */ 373 public String getServerName() { 374 return serverName; 375 } 376 377 /** 378 * Set the serverName (DataSource name) for which this transaction will be. If 379 * the serverName is not specified (left null) then the default server will be 380 * used. 381 */ 382 public TxScope setServerName(String serverName) { 383 this.serverName = serverName; 384 return this; 385 } 386 387 /** 388 * Return the throwable's that should cause a rollback. 389 */ 390 public ArrayList<Class<? extends Throwable>> getRollbackFor() { 391 return rollbackFor; 392 } 393 394 /** 395 * Set a Throwable that should explicitly cause a rollback. 396 */ 397 public TxScope setRollbackFor(Class<? extends Throwable> rollbackThrowable) { 398 if (rollbackFor == null) { 399 rollbackFor = new ArrayList<>(2); 400 } 401 rollbackFor.add(rollbackThrowable); 402 return this; 403 } 404 405 /** 406 * Set multiple throwable's that will cause a rollback. 407 */ 408 @SuppressWarnings("unchecked") 409 public TxScope setRollbackFor(Class<?>[] rollbackThrowables) { 410 if (rollbackFor == null) { 411 rollbackFor = new ArrayList<>(rollbackThrowables.length); 412 } 413 for (Class<?> rollbackThrowable : rollbackThrowables) { 414 rollbackFor.add((Class<? extends Throwable>) rollbackThrowable); 415 } 416 return this; 417 } 418 419 /** 420 * Return the throwable's that should NOT cause a rollback. 421 */ 422 public ArrayList<Class<? extends Throwable>> getNoRollbackFor() { 423 return noRollbackFor; 424 } 425 426 /** 427 * Add a Throwable to a list that will NOT cause a rollback. You are able to 428 * call this method multiple times with different throwable's and they will 429 * added to a list. 430 */ 431 public TxScope setNoRollbackFor(Class<? extends Throwable> noRollback) { 432 if (noRollbackFor == null) { 433 noRollbackFor = new ArrayList<>(2); 434 } 435 this.noRollbackFor.add(noRollback); 436 return this; 437 } 438 439 /** 440 * Set multiple throwable's that will NOT cause a rollback. 441 */ 442 @SuppressWarnings("unchecked") 443 public TxScope setNoRollbackFor(Class<?>[] noRollbacks) { 444 if (noRollbackFor == null) { 445 noRollbackFor = new ArrayList<>(noRollbacks.length); 446 } 447 for (Class<?> noRollback : noRollbacks) { 448 noRollbackFor.add((Class<? extends Throwable>) noRollback); 449 } 450 return this; 451 } 452 453 public boolean isBatchMode() { 454 return PersistBatch.ALL.equals(batch); 455 } 456 457 public boolean isBatchOnCascade() { 458 return PersistBatch.ALL.equals(batchOnCascade); 459 } 460}