Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transaction suspend does not delist resources on JBoss [SPR-1206] #5909

Closed
spring-issuemaster opened this Issue Aug 5, 2005 · 8 comments

Comments

Projects
None yet
2 participants
@spring-issuemaster
Copy link
Collaborator

spring-issuemaster commented Aug 5, 2005

Dmitri Maximovich opened SPR-1206 and commented

Spring's TransactionProxies behavi inconsistent under WebLogic and JBoss. See attached sources for deatils and test case (SpringTxTest).

Here is a brief explanation of use case:

  • XA DataSource created in App server
  • JtaTransactionManager defined in Spring context
  • BeanA and BeanB deployed with PROPAGATION_REQUIRES_NEW
  • BeanA has DataSource and BeanB injected
  • BeanA creates JDBC Connection from XA DataSource, executes insert into table and calls BeanB passing Connection as parameter of the call
  • BeanB, using Connection passed, executes inserts into (same) table (this is supposed to happen in new transaction)
  • BeanB throws RuntimeException (Spring is supposed to rollback BeanB's transaction)
  • BeanA catches runtime exception from BeanB and ignoring it (so BeanA transaction supposed to finish successully)

Expected result: Table has 1 record in it after test run.
Result under WebLogic: 1 record.
Result under JBoss: 2 records.

No errors in log files, Spring saying that transaction is rolled back:


[txsuspend.spring.BeanA] A: test() begin
[org.springframework.transaction.interceptor.TransactionInterceptor] Getting transaction for txsuspend.spring.IBeanB.test
[org.springframework.transaction.jta.JtaTransactionManager] Using transaction object [org.springframework.transaction.jta.JtaTransactionObject@239525]
[org.springframework.transaction.jta.JtaTransactionManager] Creating new transaction, suspending current one
[org.springframework.transaction.jta.JtaTransactionManager] Suspending JTA transaction
[org.springframework.transaction.support.TransactionSynchronizationManager] Clearing transaction synchronization
[org.springframework.transaction.jta.JtaTransactionManager] Beginning JTA transaction
[org.springframework.transaction.support.TransactionSynchronizationManager] Initializing transaction synchronization
[txsuspend.spring.BeanB] B: test() begin
[txsuspend.spring.BeanB] Throwing exception from B
[org.springframework.transaction.interceptor.RuleBasedTransactionAttribute] Applying rules to determine whether transaction should rollback on java.lang.RuntimeException: test from B
[org.springframework.transaction.interceptor.RuleBasedTransactionAttribute] Winning rollback rule is: null
[org.springframework.transaction.interceptor.RuleBasedTransactionAttribute] No relevant rollback rule found: applying superclass default
[org.springframework.transaction.interceptor.TransactionInterceptor] Invoking rollback for transaction on txsuspend.spring.IBeanB.test due to throwable [java.lang.RuntimeException: test from B]
[org.springframework.transaction.jta.JtaTransactionManager] Triggering beforeCompletion synchronization
[org.springframework.transaction.jta.JtaTransactionManager] Initiating transaction rollback
[org.springframework.transaction.jta.JtaTransactionManager] Rolling back JTA transaction
[org.springframework.transaction.jta.JtaTransactionManager] Triggering afterCompletion synchronization
[org.springframework.transaction.support.TransactionSynchronizationManager] Clearing transaction synchronization
[org.springframework.transaction.jta.JtaTransactionManager] Resuming suspended transaction
[org.springframework.transaction.support.TransactionSynchronizationManager] Initializing transaction synchronization
[org.springframework.transaction.jta.JtaTransactionManager] Resuming JTA transaction
[txsuspend.spring.BeanA] Exception from BeanB cached, ignoring
[txsuspend.spring.BeanA] A: test() done
[org.springframework.transaction.interceptor.TransactionInterceptor] Invoking commit for transaction on txsuspend.spring.IBeanA.test
[org.springframework.transaction.jta.JtaTransactionManager] Triggering beforeCommit synchronization
[org.springframework.transaction.jta.JtaTransactionManager] Triggering beforeCompletion synchronization
[org.springframework.transaction.jta.JtaTransactionManager] Initiating transaction commit
[org.springframework.transaction.jta.JtaTransactionManager] Committing JTA transaction
[org.springframework.transaction.jta.JtaTransactionManager] Triggering afterCompletion synchronization
[org.springframework.transaction.support.TransactionSynchronizationManager] Clearing transaction synchronization



Affects: 1.2.3

Attachments:

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Aug 5, 2005

Dmitri Maximovich commented

Test Case

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Aug 5, 2005

Dmitri Maximovich commented

Juergen,

I think it can be related to the fact that JBoss doesn't seems to delist (call XAResource.end(xid, TMSUSPEND)) resources on TransactionManager.suspend() call, at least that't what they say in documentation:
http://docs.jboss.com/jbossas/javadoc/4.0.1-sp1/transaction/org/jboss/tm/TxManager.html#suspend()

Actually, the same problem could be reproduced with this simple test (I beliebe that's exactly what's happening in Spring?):


// JBoss
UserTransaction userTransaction = (UserTransaction)Locator.lookup("java:comp/UserTransaction");
TransactionManager tm = (TransactionManager)Locator.lookup("java:/TransactionManager");
DataSource dataSource = Locator.getDataSource("java:/TXDataSource");

userTransaction.begin();

Connection connection = dataSource.getConnection();

doSmth(connection, "A");

// suspend
Transaction transaction = tm.suspend();

// start another transaction
userTransaction.begin();

doSmth(connection, "B");

userTransaction.rollback();

// resume first tx
tm.resume(transaction);

userTransaction.commit();


The result is 2 records in the table!
Any thoughts?

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Aug 5, 2005

Juergen Hoeller commented

This is indeed odd. However, it doesn't surprise me on JBoss: I recently had an issue in a project where JBoss did not enlist resources in a new transaction if you fetched the resources before transaction begin - at least not for more than one transaction. No suspension there, just a single Connection supposed to be used for multiple subsequent transactions. Not sure whether that still doesn't work on JBoss 4, but it's kind of consistent if transaction suspension doesn't work on the same Connection either then.

I guess the only way to make this work on JBoss is to fetch the Connections only during the respective current transaction. So if your subtransaction would fetch a new Connection and perform its work on that, I suppose it would execute correctly.

Juergen

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Aug 8, 2005

Dmitri Maximovich commented

Juergen,

I have opened a bug for JBoss, and it's been rejected, details are here:

http://jira.jboss.com/jira/browse/JBAS-2080

Looks like JBoss guys thinks that this is correct behavior as per spec (which is indeed says that TransactionManager.suspend() just de-associates thread with transactional context without sending any commands to XAResources participating).

What bothers me (again) is that Spring doesn't give you any warning that this is happening. Expected behaviour is not consistent across app. servers. Do you think it can be done better???

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Aug 8, 2005

Juergen Hoeller commented

Does this mean that passing along a Connection doesn't work with JBoss EJB CMT RequiresNew either? I assume that JBoss EJB CMT just performs a TransactionManager.suspend() call as well... Do you have a chance to give that a try?

I'm afraid we can't do much about that from the Spring side of things. Spring simply doesn't know whether TransactionManager.suspend() performs a full delistment of all resources as well. It can only assume that full delistment happened...

Would it work for you to simply fetch a new Connection for every subtransaction, relying on DataSource.getConnection()? That should correctly work in JBoss as well, and is generally the recommended usage pattern.

Juergen

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Aug 8, 2005

Dmitri Maximovich commented

I realize that I can fetch fresh Connection in every (sub) transaction, and personally I always doing just that. This is not my use case but rather ongoing experiments with TransactionManager functionality in different containers. There is nothing wrong with passing Connection over tx boundaries, nothing in the spec is prohibiting this.

I still think that even if Spring (obviously) cannot recover from this problem, it may know that such problem exists in certain containers and at least print warning, say on initialization time when there are proxies with REQUIRES_NEW or NOT_SUPPORTED defined in context being loaded and it runs under JBoss? That would lead to much nicer user experience for framework which suppose to 'simplify J2EE'. Don't you agree? Otherwise users could spend long time trying to understand why their transactions doesn't work as they should and would be left with a bad taste in their mouth even there is nothing really to blame Spring for.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Aug 8, 2005

Dmitri Maximovich commented

Same results when using Session Beans/CMT in JBoss

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Aug 8, 2005

Juergen Hoeller commented

Verified to be general JBoss behavior and thus a JBoss issue. Spring on JBoss is consistent with JBoss EJB CMT in that respect. JBoss's TransactionManager unfortunately doesn't deliver the resource enlistment/delistment semantics that one would expect here.

Juergen

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.