You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@geronimo.apache.org by James Richardson <ja...@time4tea.net> on 2007/01/21 19:53:27 UTC

Geronimo Transaction Management - not spec compliant?

Hi,

I recently posted the following to the Spring Support Forum. I wondered 
if you Geronimo guys would be interested too. I solved the issue by 
using the JOTM transaction manager, it worked immediately with no 
problems. - I do need to use Jencks though for its pooled managed 
connection classes so it would be nice to use the geronimo transaction 
manager to keep from using so many different packages...

Is the behaviour here compliant, or is is a spring misinterpretation?

Thanks!

James

--------------------------------
Hi there,

Would really appreciate a little bit of direction on a problem that has 
completely got me stuck.

I'm trying to implement Jencks, ActiveMQ, and Hibernate using the Spring 
HibernateTemplate. I have successfully got activemq delivering messages 
to the application.

However, when rolling back the transactionmanager's transaction, only 
the activemq transaction seems to be rolled back, not the hibernate one.

Having spent quite some time looking at this, I find the following 
behaviour:

I realise that there is a two-phase commit process happening, but am 
seeing something that doesn't quite seem to look right. Perhaps this is 
a red herring...

Within a JCA transaction, I call rollback() or setRollbackOnly(). 
Eventually the thread's stack looks like this:

beforeCommit (SpringSessionSynchronization)
beforeCompletion (SessionFactoryUtils$StateSessionSynchronization)
beforeCompletion (SessionFactoryUtils$JtaSessionSynchronization)
beforeCompletion (org.apache.geronimo.transaction.manager.Transacti onImpl)
rollback (org.apache.geronimo.transaction.manager.Transacti onManagerImpl)

So, it looks like on a rollback(), the beforeCompletion() method is 
being called... Geronimo is doing this. Is it doing the right thing?

Thanks for any help!

James


---------------------------------
Without posting all the configuration - which is a little complex to 
extract (but can do later if needs be) - it seems that the comments in 
the SessionFactoryUtils$JtaSessionSynchronization do not match up with 
observed behaviour. I'm wondering if this is why the hibernate session 
gets committed, when the transaction is in rollback mode.

I wrote a little testcase to show how what happens when the transaction 
is rolled back, and can't match this up with the Spring behaviour. I am 
not an expert on any of this by a long way - so may be missing the point 
completely.

So I guess I'm asking, does this seem like a misconfiguration on my part 
- or does it look like a bug (either in spring or geronimo)?

Thanks once again.

James


 From [B]SessionFactoryUtils$JtaSessionSynchronization[/B]
[code]
    /**
         * JTA beforeCompletion callback: just invoked on commit.
         * <p>In case of an exception, the JTA transaction gets set to 
rollback-only.
         * (Synchronization.beforeCompletion is not supposed to throw an 
exception.)
         * @see SpringSessionSynchronization#beforeCommit
         */
        public void beforeCompletion() {
            try {
                boolean readOnly = 
TransactionSynchronizationManager.isCurrentTransactionReadOnly();
                this.springSessionSynchronization.beforeCommit(readOnly);
            }
            catch (Throwable ex) {
                logger.error("beforeCommit callback threw exception", ex);
                try {
                    this.jtaTransactionManager.setRollbackOnly();
                }
                catch (SystemException ex2) {
                    logger.error("Could not set JTA transaction 
rollback-only", ex2);
                }
            }
            // Unbind the SessionHolder from the thread early, to avoid 
issues
            // with strict JTA implementations that issue warnings when 
doing JDBC
            // operations after transaction completion (e.g. 
Connection.getWarnings).
            this.beforeCompletionCalled = true;
            this.springSessionSynchronization.beforeCompletion();
        }



[/code]

[B]Testcase [/B]
[code]
    public void testFindOutHowSynchronizationWorks() throws Exception {
        final GeronimoTransactionManager transactionManager = 
createTxManager();

        transactionManager.begin();

        Transaction transaction = transactionManager.getTransaction();

        transaction.registerSynchronization(new Synchronization() {
            public void beforeCompletion() {
                
System.out.println("HibernateTransactionsTest.beforeCompletion");
                printStatus(transactionManager);
            }

            public void afterCompletion(int i) {
                
System.out.println("HibernateTransactionsTest.afterCompletion");
                printStatus(transactionManager);
            }
        });

        transactionManager.rollback();
    }

    private void printStatus(TransactionManager transactionManager) {
        int status = 0;
        try {
            status = transactionManager.getTransaction().getStatus();
        } catch (SystemException e) {
            System.out.println("???" + e.toString());
        }
        switch (status) {

            case Status.STATUS_ACTIVE:
                System.out.println("active");
                break;
            case Status.STATUS_ROLLEDBACK:
            case Status.STATUS_ROLLING_BACK:
            case Status.STATUS_MARKED_ROLLBACK:
                System.out.println("rolling back");
                break;
            case Status.STATUS_COMMITTED:
            case Status.STATUS_COMMITTING:
                System.out.println("committing");
                break;

            default:
                System.out.println("something else " + status );
        }
    }

    private GeronimoTransactionManager createTxManager() throws Exception {
        XidFactoryImpl xidFactory = new XidFactoryImpl();
        int transactionTimoutSeconds = 10;
        return new 
GeronimoPlatformTransactionManager(transactionTimoutSeconds, xidFactory, 
GeronimoDefaults.createTransactionLog(xidFactory, null), null);
    }

[/code]


Re: Geronimo Transaction Management - not spec compliant?

Posted by James Richardson <ja...@time4tea.net>.

> I find the text of the jta 1.0.1B spec somewhat unclear on this but I
> notice on p. 63 in the change history for 1.0.1B they changed the
> description of when to call Synchronization.beforeCompletion from
> "before the start of the transaction completion process" to "before
> the start of the two-phase transaction commit process" so I think
> there's at least an implication that we shouldn't call
> beforeCompletion when we know we're going to rollback.
>
> I imagine the problem is that hibernate tries to use something that
> objects because it's set rollbackOnly?
>
> Which version of geronimo is your version of jencks using?
>
> Would you like to file a jira issue for this?
>
> thanks
> david jencks
>

Hi David - Thanks for your quick reply.

I think that it might be worth filing a JIRA for this - I will post this
info into it.

Interestingly, the test code fails with NPE when using JOTM in the
afterCompletion method, as the TM will no longer supply a transaction to
getStatus() on, and you need to use the supplied result code.

Its interesting that activemq works though; i'll forward this to logicblaze.

Best Regards,

James



Re: Geronimo Transaction Management - not spec compliant?

Posted by David Jencks <da...@yahoo.com>.
On Jan 21, 2007, at 10:53 AM, James Richardson wrote:

> Hi,
>
> I recently posted the following to the Spring Support Forum. I  
> wondered if you Geronimo guys would be interested too. I solved the  
> issue by using the JOTM transaction manager, it worked immediately  
> with no problems. - I do need to use Jencks though for its pooled  
> managed connection classes so it would be nice to use the geronimo  
> transaction manager to keep from using so many different packages...
>
> Is the behaviour here compliant, or is is a spring misinterpretation?

I find the text of the jta 1.0.1B spec somewhat unclear on this but I  
notice on p. 63 in the change history for 1.0.1B they changed the  
description of when to call Synchronization.beforeCompletion from  
"before the start of the transaction completion process" to "before  
the start of the two-phase transaction commit process" so I think  
there's at least an implication that we shouldn't call  
beforeCompletion when we know we're going to rollback.

I imagine the problem is that hibernate tries to use something that  
objects because it's set rollbackOnly?

Which version of geronimo is your version of jencks using?

Would you like to file a jira issue for this?

thanks
david jencks

>
> Thanks!
>
> James
>
> --------------------------------
> Hi there,
>
> Would really appreciate a little bit of direction on a problem that  
> has completely got me stuck.
>
> I'm trying to implement Jencks, ActiveMQ, and Hibernate using the  
> Spring HibernateTemplate. I have successfully got activemq  
> delivering messages to the application.
>
> However, when rolling back the transactionmanager's transaction,  
> only the activemq transaction seems to be rolled back, not the  
> hibernate one.
>
> Having spent quite some time looking at this, I find the following  
> behaviour:
>
> I realise that there is a two-phase commit process happening, but  
> am seeing something that doesn't quite seem to look right. Perhaps  
> this is a red herring...
>
> Within a JCA transaction, I call rollback() or setRollbackOnly().  
> Eventually the thread's stack looks like this:
>
> beforeCommit (SpringSessionSynchronization)
> beforeCompletion (SessionFactoryUtils$StateSessionSynchronization)
> beforeCompletion (SessionFactoryUtils$JtaSessionSynchronization)
> beforeCompletion (org.apache.geronimo.transaction.manager.Transacti  
> onImpl)
> rollback (org.apache.geronimo.transaction.manager.Transacti  
> onManagerImpl)
>
> So, it looks like on a rollback(), the beforeCompletion() method is  
> being called... Geronimo is doing this. Is it doing the right thing?
>
> Thanks for any help!
>
> James
>
>
> ---------------------------------
> Without posting all the configuration - which is a little complex  
> to extract (but can do later if needs be) - it seems that the  
> comments in the SessionFactoryUtils$JtaSessionSynchronization do  
> not match up with observed behaviour. I'm wondering if this is why  
> the hibernate session gets committed, when the transaction is in  
> rollback mode.
>
> I wrote a little testcase to show how what happens when the  
> transaction is rolled back, and can't match this up with the Spring  
> behaviour. I am not an expert on any of this by a long way - so may  
> be missing the point completely.
>
> So I guess I'm asking, does this seem like a misconfiguration on my  
> part - or does it look like a bug (either in spring or geronimo)?
>
> Thanks once again.
>
> James
>
>
> From [B]SessionFactoryUtils$JtaSessionSynchronization[/B]
> [code]
>    /**
>         * JTA beforeCompletion callback: just invoked on commit.
>         * <p>In case of an exception, the JTA transaction gets set  
> to rollback-only.
>         * (Synchronization.beforeCompletion is not supposed to  
> throw an exception.)
>         * @see SpringSessionSynchronization#beforeCommit
>         */
>        public void beforeCompletion() {
>            try {
>                boolean readOnly =  
> TransactionSynchronizationManager.isCurrentTransactionReadOnly();
>                this.springSessionSynchronization.beforeCommit 
> (readOnly);
>            }
>            catch (Throwable ex) {
>                logger.error("beforeCommit callback threw  
> exception", ex);
>                try {
>                    this.jtaTransactionManager.setRollbackOnly();
>                }
>                catch (SystemException ex2) {
>                    logger.error("Could not set JTA transaction  
> rollback-only", ex2);
>                }
>            }
>            // Unbind the SessionHolder from the thread early, to  
> avoid issues
>            // with strict JTA implementations that issue warnings  
> when doing JDBC
>            // operations after transaction completion (e.g.  
> Connection.getWarnings).
>            this.beforeCompletionCalled = true;
>            this.springSessionSynchronization.beforeCompletion();
>        }
>
>
>
> [/code]
>
> [B]Testcase [/B]
> [code]
>    public void testFindOutHowSynchronizationWorks() throws Exception {
>        final GeronimoTransactionManager transactionManager =  
> createTxManager();
>
>        transactionManager.begin();
>
>        Transaction transaction = transactionManager.getTransaction();
>
>        transaction.registerSynchronization(new Synchronization() {
>            public void beforeCompletion() {
>                System.out.println 
> ("HibernateTransactionsTest.beforeCompletion");
>                printStatus(transactionManager);
>            }
>
>            public void afterCompletion(int i) {
>                System.out.println 
> ("HibernateTransactionsTest.afterCompletion");
>                printStatus(transactionManager);
>            }
>        });
>
>        transactionManager.rollback();
>    }
>
>    private void printStatus(TransactionManager transactionManager) {
>        int status = 0;
>        try {
>            status = transactionManager.getTransaction().getStatus();
>        } catch (SystemException e) {
>            System.out.println("???" + e.toString());
>        }
>        switch (status) {
>
>            case Status.STATUS_ACTIVE:
>                System.out.println("active");
>                break;
>            case Status.STATUS_ROLLEDBACK:
>            case Status.STATUS_ROLLING_BACK:
>            case Status.STATUS_MARKED_ROLLBACK:
>                System.out.println("rolling back");
>                break;
>            case Status.STATUS_COMMITTED:
>            case Status.STATUS_COMMITTING:
>                System.out.println("committing");
>                break;
>
>            default:
>                System.out.println("something else " + status );
>        }
>    }
>
>    private GeronimoTransactionManager createTxManager() throws  
> Exception {
>        XidFactoryImpl xidFactory = new XidFactoryImpl();
>        int transactionTimoutSeconds = 10;
>        return new GeronimoPlatformTransactionManager 
> (transactionTimoutSeconds, xidFactory,  
> GeronimoDefaults.createTransactionLog(xidFactory, null), null);
>    }
>
> [/code]
>