List of usage examples for org.springframework.transaction.support DefaultTransactionStatus setRollbackOnly
@Override public void setRollbackOnly()
From source file:net.sf.mmm.orient.db.impl.OrientPlatformTransactionManager.java
@Override protected void doSetRollbackOnly(DefaultTransactionStatus status) throws TransactionException { status.setRollbackOnly(); OrientTx.of(status).setRollbackOnly(); }
From source file:org.ops4j.orient.spring.tx.OrientTransactionManager.java
@Override protected void doSetRollbackOnly(DefaultTransactionStatus status) throws TransactionException { status.setRollbackOnly(); }
From source file:com.newmainsoftech.spray.slingong.datastore.Slim3PlatformTransactionManager.java
@Override protected void doSetRollbackOnly(DefaultTransactionStatus status) throws TransactionException { String message = String.format("Setting roll-back-only flag(s) up:"); /*//from w w w. ja va 2 s. c o m * Set AbstractTransactionStatus's rollbackOnly member field to true * what will make DefaultTransactionStatus's isLocalRollbackOnly method * returns true. AbstractPlatformTransactionManager's commit method * initiate roll back when its isLocalRollbackOnly method returns true. * * However, the analysis of the AbstractPlatformTransactionManager's * logic flow makes me doubt calling this method will never occurs: * * About the case called by processRollback method (that will be called * by commit method): commit method calls processRollback method when * DefaultTransactionStatus's isLocalRollbackOnly method returns true. * DefaultTransactionStatus's isLocalRollbackOnly method is also called by * processRollback method, in order for participating transaction to set * rollbackOnly member field what is done by calling this * doSetRollbackOnly method. Hence, it doesn't make much sense for this * case since, in that logic only, this will never be called. * * About the case called by doRollbackOnCommitException method (that * will be called by processRollback method): When it's participating * transaction and globalRollbackOnParticipationFailure flag value is * true, then this method is called by doRollbackOnCommitException * method. The default value of globalRollbackOnParticipationFailure * flag is true what means that the transaction originator cannot make * the transaction commit anymore once the transaction marked globally * as rollback-only. However, doRollbackOnCommitException method is * called by processCommit method and, according to Spring's * AbstractPlatformTransactionManager document (@see * http://static.springsource * .org/spring/docs/current/api/org/springframework * /transaction/support/AbstractPlatformTransactionManager * .html#setRollbackOnCommitFailure%28boolean%29) the roll back on * commit failure typically not necessary and thus to be avoided, as it * can potentially override the commit exception with a subsequent * rollback exception. I would take this as it means rather * intentionally initiating roll back after recognizing commit failure * is the recommended way than letting Spring automatically roll back * after commit failure, however it does not make sense since, because * commit is automatically handled by Spring, how it can know when and * how to roll back. It should be automatically rolled back by Spring * when failure occurs on the commit that Spring automatically performs. */ status.setRollbackOnly(); message = message + String.format("%n%tDefaultTransactionStatus object is marked as roll-back-only."); GlobalTransaction gtx = (GlobalTransaction) status.getTransaction(); if (gtx instanceof GlobalTransaction) { String gtxIdStr = gtx.getId(); Slim3GlobalTransactionObject slim3GtxObj = slim3GtxObjMapThreadLocal.get().get(gtxIdStr); if (slim3GtxObj != null) { slim3GtxObj.setRollbackOnly(true); slim3GtxObjMapThreadLocal.get().put(gtxIdStr, slim3GtxObj); message = message + String .format("%n%tSlim3GlobalTransactionObject object for GlobalTransaction instance (ID:%1$s) " + "is marked as roll-back-only.", gtxIdStr); } else { if (logger.isWarnEnabled()) { logger.warn( String.format("Inconsistent system state: GlobalTransaction instance (ID:%1$s) held " + "by state DefaultTransactionStatus argument is not among ones managed " + "by %2$s.", gtxIdStr, this.getClass().getName())); } } } if (logger.isInfoEnabled()) logger.info(message); }
From source file:com.newmainsoftech.spray.slingong.datastore.Slim3PlatformTransactionManager.java
@Override protected void doCommit(DefaultTransactionStatus defaultTransactionStatus) throws TransactionException { GlobalTransaction gtx = (GlobalTransaction) defaultTransactionStatus.getTransaction(); Set<GlobalTransactionState> gtxStateSet = getGlobalTransactionStates(gtx); // Sanity check on precondition ----------------------------------------------------------- /*/* w w w .j a va 2 s .c o m*/ * This will be called at outermost transaction boundary (defaultTransactionStatus.isNewTransaction() * will return true). * When defaultTransactionStatus has been set for roll back, roll back doesn't need to be handled * within doCommit method. * When either defaultTransactionStatus's isGlobalRollbackOnly and shouldCommitOnGlobalRollbackOnly * returns true or its isLocalRollbackOnly returns true, then logic flow won't reach here and * roll back should have been performed by doRollback. */ if (defaultTransactionStatus.isRollbackOnly()) { throw new TransactionSystemException(String.format( "Unexpected system state: the transaction for the GlobalTransaction " + "instance (ID:%1$s) has been marked as roll-back only " + "(LocalRollbackOnly:%2$b, GlobalRollbackOnly:%3$b).", (gtxStateSet.contains(GlobalTransactionState.GlobalTransactionInstance) ? gtx.getId() : "null"), defaultTransactionStatus.isLocalRollbackOnly(), defaultTransactionStatus.isGlobalRollbackOnly())); } if (!defaultTransactionStatus.isNewTransaction()) { throw new TransactionSystemException(String.format( "Unexpected system state: attempted to commit from participation of an existing " + "transaction (of which GlobalTransacion Id is %1$s).", (gtxStateSet.contains(GlobalTransactionState.GlobalTransactionInstance) ? gtx.getId() : "null"))); } // ---------------------------------------------------------------------------------------- // Sanity check on gtx GlobalTransaction instance ----------------------------------------- if (!gtxStateSet.contains(GlobalTransactionState.ActiveGlobalTransaction)) { String message; if (!gtxStateSet.contains(GlobalTransactionState.GlobalTransactionInstance)) { message = "Unexpected system state: The GlobalTransaction object passed as the transaction " + "Object argument is null."; } else { message = String .format("Unexpected system state: The GlobalTransaction instance (ID:%1$s) passed as the " + "transaction Object argument is inactive.", gtx.getId()); } throw new IllegalTransactionStateException(message); } if (!gtxStateSet.contains(GlobalTransactionState.CurrentGlobalTransaction)) { /* The one possible case of the control flow reaching here is that GlobalTransaction object * is manually instantiated at the outside of Spring transaction framework, and it is left active. * * In nesting global transaction, easy to yield ConcurrentModificationException without care. * Nesting global transaction should be less necessary, since Slim3 isolate between (Global) * transactions and cannot change that isolation setting, and this uses Slim3 GlobalTransaction, * as GAE/J datastore API is not provide suspend feature as well. */ GlobalTransaction currentGtx = Datastore.getCurrentGlobalTransaction(); if (logger.isWarnEnabled()) { logger.warn(String.format( "Though active GlobalTransaction instance (ID:%1$s) is passed as transaction " + "Object argument, it's not current GlobalTransaction instance (ID:%2$s).", gtx.getId(), ((currentGtx instanceof GlobalTransaction) ? currentGtx.getId() : "null"))); } } // ---------------------------------------------------------------------------------------- boolean exceptionUp = false; try { gtx.commit(); slim3GtxObjMapThreadLocal.get().remove(gtx.getId()); if (logger.isInfoEnabled()) { logger.info(String.format("Slim3 GlobalTransaction (ID:%1$s) committed.", gtx.getId())); } } catch (Throwable throwable) { /* Set rollback only flag so calling processRollback method to roll back will occur at * commit method by AnnotationTransactionAspect, even for other exceptions than ones specified * for rollbackFor or rollbackForClassname attributes of @Transactional annotation. */ defaultTransactionStatus.setRollbackOnly(); exceptionUp = true; String message = String.format("Slim3 GlobalTransaction (ID:%1$s) failed on commit.", gtx.getId()); if ((throwable instanceof ConcurrentModificationException) || (throwable instanceof DeadlineExceededException)) { /* Slim3 should have already rolled back automatically on either * ConcurrentModificationException or DeadlineExceededException. * * About DeadlineExceededException case: It seems like no harm * will be made even active global transaction at * DeadlineExceededException case left behind. As looking * briefly through the Slim3 source codes, the locks by that * global transaction seems to be released while it rolls back * by DatastoreFilter, and itself seem to be removed from * TheadLocal stack of the global transactions. So, it won't be * returned by such Datastore.getCurrentGlobalTransaction() * method. See at * http://groups.google.com/group/slim3-user/browse_frm * /thread/e3d47d8f28c8e8d3 * /9e43553f3b56d1f2?tvc=1#9e43553f3b56d1f2 If it turns out * opposite, then that active global transaction can be cleared * some how at here for DeadlineExceededException case. */ message = String.format("Slim3 GlobalTransaction (ID:%1$s) failed on commit. %n" + "Slim3 must have already rolled back automatically behind " + "Spring transaction framework.", gtx.getId()); } throw new TransactionSystemException(message, throwable); } finally { if (gtx.isActive()) { if (exceptionUp) { if (logger.isInfoEnabled()) { logger.info(String.format( "GlobalTransaction instance (ID:%1$s) remains active after exception " + "durring commit attempt. That GlobalTransaction instance has not " + "been removed yet from slim3GtxObjMapThreadLocal member field.", gtx.getId(), this.getClass().getName())); } } else { if (logger.isWarnEnabled()) { logger.warn(String.format( "Unexpected system state: GlobalTransaction instance (ID:%1$s) " + "remains active even after commit attempt. That GlobalTransaction " + "instance was removed from slim3GtxObjMapThreadLocal member field.", gtx.getId(), this.getClass().getName())); } } } } }
From source file:org.springframework.batch.core.step.item.FaultTolerantStepFactoryBeanUnexpectedRollbackTests.java
@Test @Ignore //FIXME/*from w w w. java 2s . c o m*/ public void testTransactionException() throws Exception { final SkipWriterStub<String> writer = new SkipWriterStub<String>(); FaultTolerantStepFactoryBean<String, String> factory = new FaultTolerantStepFactoryBean<String, String>(); factory.setItemWriter(writer); @SuppressWarnings("serial") DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource) { private boolean failed = false; @Override protected void doCommit(DefaultTransactionStatus status) throws TransactionException { if (writer.getWritten().isEmpty() || failed || !isExistingTransaction(status.getTransaction())) { super.doCommit(status); return; } failed = true; status.setRollbackOnly(); super.doRollback(status); throw new UnexpectedRollbackException("Planned"); } }; factory.setBeanName("stepName"); factory.setTransactionManager(transactionManager); factory.setCommitInterval(2); ItemReader<String> reader = new ListItemReader<String>(Arrays.asList("1", "2")); factory.setItemReader(reader); JobRepositoryFactoryBean repositoryFactory = new JobRepositoryFactoryBean(); repositoryFactory.setDataSource(dataSource); repositoryFactory.setTransactionManager(transactionManager); repositoryFactory.afterPropertiesSet(); JobRepository repository = repositoryFactory.getObject(); factory.setJobRepository(repository); JobExecution jobExecution = repository.createJobExecution("job", new JobParameters()); StepExecution stepExecution = jobExecution.createStepExecution(factory.getName()); repository.add(stepExecution); Step step = factory.getObject(); step.execute(stepExecution); assertEquals(BatchStatus.FAILED, stepExecution.getStatus()); assertEquals("[]", writer.getCommitted().toString()); }