You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user-java@ibatis.apache.org by Alistair Young <al...@gmail.com> on 2008/04/08 16:02:45 UTC

Another JTA question - nested transactions

Hello again,

After figuring out my previous problem, I've got my iBATIS/JTA test
application working up to a point (start transaction, update followed
by end or commit).

Now, according to the book "iBATIS in Action", when configured to use
a JTA transactionManager, "iBATIS will look for the global transaction
context and attempt to manage it appropriately.  This means that
iBATIS can check the state of an existing transaction or start one if
necessary."  It also states that "you should still start, commit and
end the 'inner transaction scope'".

Given this, I'd expected to be able to write code like this;

       // start a transaction
       // [iBATIS starts a new JTA transaction...?]
       sqlMapClient.startTransaction();

       // ... do some database processing ...

       // start an inner transaction
       // [iBATIS joins the existing JTA transaction...?]
       sqlMapClient.startTransaction();

       // ... do some more database processing ...

       // abandon the inner transaction
       // [iBATIS issues setRollbackOnly on JTA transaction...?]
       sqlMapClient.endTransaction();

       // commit the outer transaction
       // [iBATIS issues commit on JTA transaction...?]
       sqlMapClient.commitTransaction();

with the final result that the database is unchanged.  However,
instead, I get an exception on my second call to startTransaction()
complaining that a transaction is already started.

Obviously what I'm ultimately looking to do is to coordinate a number
of distinct database interactions into a single transaction - but this
example demonstrates my problem, I think.

Can anybody suggest how I might achieve this?

Thanks again,


Alistair.

Re: Another JTA question - nested transactions

Posted by Alistair Young <al...@gmail.com>.
Thanks for the suggestion, Clinton - I shall have an experiment with
that approach.  (Very handy book too, by the way!)


Alistair.

On 08/04/2008, Clinton Begin <cl...@gmail.com> wrote:
> I usually suggest just using the EXTERNAL transaction manager and let your
> container manage the transaction entirely.  I'm pretty sure this works well
> for most people.
>
> Clinton
>
>
> On Tue, Apr 8, 2008 at 10:18 AM, Jeff Butler <je...@gmail.com> wrote:
>
> >
> > iBATIS does not support nested transactions.  Take a look at the class
> com.ibatis.sqlmap.engine.transaction.jta.JtaTransaction to
> see what's going on.
> >
> > If a JTA transaction already exists...
> >
> > 1. The iBATIS "startTransaction" will not start another transaction
> > 2. The iBATIS commit does nothing
> > 3. The iBATIS rollback marks the transaction for rollback, but does not
> rollback itself
> >
> > When there are externally managed transactions, the iBATIS rollback will
> mark the external transaction for rollback, but the other two methods do,
> essentially, nothing.
> >
> > Jeff Butler
> >
> >
> >
> >
> >
> > On Tue, Apr 8, 2008 at 9:44 AM, Alistair Young
> <al...@gmail.com> wrote:
> >
> > > Once again I seem to have found a solution shortly after asking the
> question...
> > >
> > > On 08/04/2008, Alistair Young <al...@gmail.com> wrote:
> > > > [ ... snip ... ]
> > >
> > > >
> > > >        // start a transaction
> > > >        // [iBATIS starts a new JTA transaction...?]
> > > >        sqlMapClient.startTransaction();
> > > >
> > > >        // ... do some database processing ...
> > > >
> > > >        // start an inner transaction
> > > >        // [iBATIS joins the existing JTA transaction...?]
> > > >        sqlMapClient.startTransaction();
> > > >
> > > >        // ... do some more database processing ...
> > > >
> > > >        // abandon the inner transaction
> > > >        // [iBATIS issues setRollbackOnly on JTA transaction...?]
> > > >        sqlMapClient.endTransaction();
> > > >
> > > >        // commit the outer transaction
> > > >        // [iBATIS issues commit on JTA transaction...?]
> > > >        sqlMapClient.commitTransaction();
> > > >
> > > >  with the final result that the database is unchanged.  However,
> > > >  instead, I get an exception on my second call to startTransaction()
> > > >  complaining that a transaction is already started.
> > > >
> > > >  [ ... snip ... ]
> > >
> > > After a bit of experimentation, I think that I need to explicitly
> > > start the JTA transaction outside of the iBATIS transactions.  The
> > > following does what I'd expected:
> > >
> > >       // start a JTA transaction
> > >       Context ctx = new InitialContext();
> > >       UserTransaction ut =
> > >
> (UserTransaction)ctx.lookup("java:comp/UserTransaction");
> > >       ut.begin();
> > >
> > >       // start an iBATIS transaction
> > >       // [iBATIS joins the JTA transaction]
> > >
> > >       sqlMapClient.startTransaction();
> > >
> > >       // ... do some database processing ...
> > >
> > >       // commit the iBATIS transaction
> > >       // [iBATIS does not actually commit to the db]
> > >       sqlMapClient.commitTransaction();
> > >
> > >       // start another iBATIS transaction
> > >       // [iBATIS joins the JTA transaction]
> > >
> > >       sqlMapClient.startTransaction();
> > >
> > >       // ... do some more database processing ...
> > >
> > >       // abandon the iBATIS transaction
> > >
> > >       // [iBATIS issues setRollbackOnly on JTA transaction]
> > >       sqlMapClient.endTransaction();
> > >
> > >       // commit the JTA transaction
> > >       try {
> > >              ut.commit();
> > >       } catch (RollbackException x) {
> > >              // will be raised because the commit did
> > >              // not take place (since the second iBATIS
> > >              // transaction was cancelled)
> > >       }
> > >
> > > Please feel free to suggest a better way, if one should exist!
> > >
> > >
> > > Alistair.
> > >
> >
> >
>
>

Re: Another JTA question - nested transactions

Posted by Clinton Begin <cl...@gmail.com>.
I usually suggest just using the EXTERNAL transaction manager and let your
container manage the transaction entirely.  I'm pretty sure this works well
for most people.

Clinton

On Tue, Apr 8, 2008 at 10:18 AM, Jeff Butler <je...@gmail.com> wrote:

> iBATIS does not support nested transactions.  Take a look at the class com.ibatis.sqlmap.engine.transaction.jta.JtaTransaction
> to see what's going on.
>
> If a JTA transaction already exists...
>
> 1. The iBATIS "startTransaction" will not start another transaction
> 2. The iBATIS commit does nothing
> 3. The iBATIS rollback marks the transaction for rollback, but does not
> rollback itself
>
> When there are externally managed transactions, the iBATIS rollback will
> mark the external transaction for rollback, but the other two methods do,
> essentially, nothing.
>
> Jeff Butler
>
> On Tue, Apr 8, 2008 at 9:44 AM, Alistair Young <al...@gmail.com>
> wrote:
>
> > Once again I seem to have found a solution shortly after asking the
> > question...
> >
> > On 08/04/2008, Alistair Young <al...@gmail.com> wrote:
> > > [ ... snip ... ]
> > >
> > >        // start a transaction
> > >        // [iBATIS starts a new JTA transaction...?]
> > >        sqlMapClient.startTransaction();
> > >
> > >        // ... do some database processing ...
> > >
> > >        // start an inner transaction
> > >        // [iBATIS joins the existing JTA transaction...?]
> > >        sqlMapClient.startTransaction();
> > >
> > >        // ... do some more database processing ...
> > >
> > >        // abandon the inner transaction
> > >        // [iBATIS issues setRollbackOnly on JTA transaction...?]
> > >        sqlMapClient.endTransaction();
> > >
> > >        // commit the outer transaction
> > >        // [iBATIS issues commit on JTA transaction...?]
> > >        sqlMapClient.commitTransaction();
> > >
> > >  with the final result that the database is unchanged.  However,
> > >  instead, I get an exception on my second call to startTransaction()
> > >  complaining that a transaction is already started.
> > >
> > >  [ ... snip ... ]
> >
> > After a bit of experimentation, I think that I need to explicitly
> > start the JTA transaction outside of the iBATIS transactions.  The
> > following does what I'd expected:
> >
> >       // start a JTA transaction
> >       Context ctx = new InitialContext();
> >       UserTransaction ut =
> > (UserTransaction)ctx.lookup("java:comp/UserTransaction");
> >       ut.begin();
> >
> >       // start an iBATIS transaction
> >       // [iBATIS joins the JTA transaction]
> >       sqlMapClient.startTransaction();
> >
> >       // ... do some database processing ...
> >
> >       // commit the iBATIS transaction
> >       // [iBATIS does not actually commit to the db]
> >       sqlMapClient.commitTransaction();
> >
> >       // start another iBATIS transaction
> >       // [iBATIS joins the JTA transaction]
> >       sqlMapClient.startTransaction();
> >
> >       // ... do some more database processing ...
> >
> >       // abandon the iBATIS transaction
> >       // [iBATIS issues setRollbackOnly on JTA transaction]
> >       sqlMapClient.endTransaction();
> >
> >       // commit the JTA transaction
> >       try {
> >              ut.commit();
> >       } catch (RollbackException x) {
> >              // will be raised because the commit did
> >              // not take place (since the second iBATIS
> >              // transaction was cancelled)
> >       }
> >
> > Please feel free to suggest a better way, if one should exist!
> >
> >
> > Alistair.
> >
>
>

Re: Another JTA question - nested transactions

Posted by Alistair Young <al...@gmail.com>.
Thanks for the tips, Jeff.  It appears, however, that although the
iBATIS "startTransaction" will not start another transaction if a JTA
transaction exists, it will still thrown an exception.  (I'd assumed -
incorrectly - that all of the transaction handling would be handed off
to JTA).

Anyway, I seem to be on the right track now!

Cheers,


Alistair.

On 08/04/2008, Jeff Butler <je...@gmail.com> wrote:
> iBATIS does not support nested transactions.  Take a look at the class
> com.ibatis.sqlmap.engine.transaction.jta.JtaTransaction to
> see what's going on.
>
> If a JTA transaction already exists...
>
> 1. The iBATIS "startTransaction" will not start another transaction
> 2. The iBATIS commit does nothing
> 3. The iBATIS rollback marks the transaction for rollback, but does not
> rollback itself
>
> When there are externally managed transactions, the iBATIS rollback will
> mark the external transaction for rollback, but the other two methods do,
> essentially, nothing.
>
> Jeff Butler
>
>
> On Tue, Apr 8, 2008 at 9:44 AM, Alistair Young <al...@gmail.com>
> wrote:
>
> > Once again I seem to have found a solution shortly after asking the
> question...
> >
> > On 08/04/2008, Alistair Young <al...@gmail.com> wrote:
> > > [ ... snip ... ]
> >
> > >
> > >        // start a transaction
> > >        // [iBATIS starts a new JTA transaction...?]
> > >        sqlMapClient.startTransaction();
> > >
> > >        // ... do some database processing ...
> > >
> > >        // start an inner transaction
> > >        // [iBATIS joins the existing JTA transaction...?]
> > >        sqlMapClient.startTransaction();
> > >
> > >        // ... do some more database processing ...
> > >
> > >        // abandon the inner transaction
> > >        // [iBATIS issues setRollbackOnly on JTA transaction...?]
> > >        sqlMapClient.endTransaction();
> > >
> > >        // commit the outer transaction
> > >        // [iBATIS issues commit on JTA transaction...?]
> > >        sqlMapClient.commitTransaction();
> > >
> > >  with the final result that the database is unchanged.  However,
> > >  instead, I get an exception on my second call to startTransaction()
> > >  complaining that a transaction is already started.
> > >
> > >  [ ... snip ... ]
> >
> > After a bit of experimentation, I think that I need to explicitly
> > start the JTA transaction outside of the iBATIS transactions.  The
> > following does what I'd expected:
> >
> >       // start a JTA transaction
> >       Context ctx = new InitialContext();
> >       UserTransaction ut =
> > (UserTransaction)ctx.lookup("java:comp/UserTransaction");
> >       ut.begin();
> >
> >       // start an iBATIS transaction
> >       // [iBATIS joins the JTA transaction]
> >
> >       sqlMapClient.startTransaction();
> >
> >       // ... do some database processing ...
> >
> >       // commit the iBATIS transaction
> >       // [iBATIS does not actually commit to the db]
> >       sqlMapClient.commitTransaction();
> >
> >       // start another iBATIS transaction
> >       // [iBATIS joins the JTA transaction]
> >
> >       sqlMapClient.startTransaction();
> >
> >       // ... do some more database processing ...
> >
> >       // abandon the iBATIS transaction
> >
> >       // [iBATIS issues setRollbackOnly on JTA transaction]
> >       sqlMapClient.endTransaction();
> >
> >       // commit the JTA transaction
> >       try {
> >              ut.commit();
> >       } catch (RollbackException x) {
> >              // will be raised because the commit did
> >              // not take place (since the second iBATIS
> >              // transaction was cancelled)
> >       }
> >
> > Please feel free to suggest a better way, if one should exist!
> >
> >
> > Alistair.
> >
>
>

Re: Another JTA question - nested transactions

Posted by Jeff Butler <je...@gmail.com>.
iBATIS does not support nested transactions.  Take a look at the class
com.ibatis.sqlmap.engine.transaction.jta.JtaTransaction
to see what's going on.

If a JTA transaction already exists...

1. The iBATIS "startTransaction" will not start another transaction
2. The iBATIS commit does nothing
3. The iBATIS rollback marks the transaction for rollback, but does not
rollback itself

When there are externally managed transactions, the iBATIS rollback will
mark the external transaction for rollback, but the other two methods do,
essentially, nothing.

Jeff Butler

On Tue, Apr 8, 2008 at 9:44 AM, Alistair Young <al...@gmail.com>
wrote:

> Once again I seem to have found a solution shortly after asking the
> question...
>
> On 08/04/2008, Alistair Young <al...@gmail.com> wrote:
> > [ ... snip ... ]
> >
> >        // start a transaction
> >        // [iBATIS starts a new JTA transaction...?]
> >        sqlMapClient.startTransaction();
> >
> >        // ... do some database processing ...
> >
> >        // start an inner transaction
> >        // [iBATIS joins the existing JTA transaction...?]
> >        sqlMapClient.startTransaction();
> >
> >        // ... do some more database processing ...
> >
> >        // abandon the inner transaction
> >        // [iBATIS issues setRollbackOnly on JTA transaction...?]
> >        sqlMapClient.endTransaction();
> >
> >        // commit the outer transaction
> >        // [iBATIS issues commit on JTA transaction...?]
> >        sqlMapClient.commitTransaction();
> >
> >  with the final result that the database is unchanged.  However,
> >  instead, I get an exception on my second call to startTransaction()
> >  complaining that a transaction is already started.
> >
> >  [ ... snip ... ]
>
> After a bit of experimentation, I think that I need to explicitly
> start the JTA transaction outside of the iBATIS transactions.  The
> following does what I'd expected:
>
>       // start a JTA transaction
>       Context ctx = new InitialContext();
>       UserTransaction ut =
> (UserTransaction)ctx.lookup("java:comp/UserTransaction");
>       ut.begin();
>
>       // start an iBATIS transaction
>       // [iBATIS joins the JTA transaction]
>       sqlMapClient.startTransaction();
>
>       // ... do some database processing ...
>
>       // commit the iBATIS transaction
>       // [iBATIS does not actually commit to the db]
>       sqlMapClient.commitTransaction();
>
>       // start another iBATIS transaction
>       // [iBATIS joins the JTA transaction]
>       sqlMapClient.startTransaction();
>
>       // ... do some more database processing ...
>
>       // abandon the iBATIS transaction
>       // [iBATIS issues setRollbackOnly on JTA transaction]
>       sqlMapClient.endTransaction();
>
>       // commit the JTA transaction
>       try {
>              ut.commit();
>       } catch (RollbackException x) {
>              // will be raised because the commit did
>              // not take place (since the second iBATIS
>              // transaction was cancelled)
>       }
>
> Please feel free to suggest a better way, if one should exist!
>
>
> Alistair.
>

Re: Another JTA question - nested transactions

Posted by Alistair Young <al...@gmail.com>.
Once again I seem to have found a solution shortly after asking the question...

On 08/04/2008, Alistair Young <al...@gmail.com> wrote:
> [ ... snip ... ]
>
>        // start a transaction
>        // [iBATIS starts a new JTA transaction...?]
>        sqlMapClient.startTransaction();
>
>        // ... do some database processing ...
>
>        // start an inner transaction
>        // [iBATIS joins the existing JTA transaction...?]
>        sqlMapClient.startTransaction();
>
>        // ... do some more database processing ...
>
>        // abandon the inner transaction
>        // [iBATIS issues setRollbackOnly on JTA transaction...?]
>        sqlMapClient.endTransaction();
>
>        // commit the outer transaction
>        // [iBATIS issues commit on JTA transaction...?]
>        sqlMapClient.commitTransaction();
>
>  with the final result that the database is unchanged.  However,
>  instead, I get an exception on my second call to startTransaction()
>  complaining that a transaction is already started.
>
>  [ ... snip ... ]

After a bit of experimentation, I think that I need to explicitly
start the JTA transaction outside of the iBATIS transactions.  The
following does what I'd expected:

       // start a JTA transaction
       Context ctx = new InitialContext();
       UserTransaction ut =
(UserTransaction)ctx.lookup("java:comp/UserTransaction");
       ut.begin();

       // start an iBATIS transaction
       // [iBATIS joins the JTA transaction]
       sqlMapClient.startTransaction();

       // ... do some database processing ...

       // commit the iBATIS transaction
       // [iBATIS does not actually commit to the db]
       sqlMapClient.commitTransaction();

       // start another iBATIS transaction
       // [iBATIS joins the JTA transaction]
       sqlMapClient.startTransaction();

       // ... do some more database processing ...

       // abandon the iBATIS transaction
       // [iBATIS issues setRollbackOnly on JTA transaction]
       sqlMapClient.endTransaction();

       // commit the JTA transaction
       try {
              ut.commit();
       } catch (RollbackException x) {
              // will be raised because the commit did
              // not take place (since the second iBATIS
              // transaction was cancelled)
       }

Please feel free to suggest a better way, if one should exist!


Alistair.