Hi Faizal, Philippe, Rohini and Alexandre,
I've investigated about the following trace:
Cannot enlist XAResource:
javax.transaction.SystemException:
Cannot send XA start:
javax.transaction.xa.XAException:
mixed transactions
Unexpected Exception on commit_one_phase:
java.rmi.RemoteException:
XAException:
javax.transaction.xa.XAException:
Cannot mix transactions
To make thing clearer, I created some small example. (The source and
deployment descriptor are attached to this mail.)
This example consists of:
jun12x.test.jonas.TxClient
jun12x.test.jonas.TxCallerSessionBean
jun12x.test.jonas.TxCalledSessionBean
and the required interfaces.
The transaction is managed by the container and the transaction
attributes for all the methods are 'Required'.
The methods are invoked in the following order:
Client --> Caller(Bean) --> Called(Bean)
After the beans are activated in JOnAS, run the client program. It
invokes the two methods on the bean according to the option.
1. java jun12x.test.jonas.TxClient -a <para_1> <para_2>
This invokes insertOnSessionAfterClosed(String, String) on
TxCallerSession, which invokes TxCalledSession.insert(String) after
Connection.close().
2. java jun12x.test.jonas.TxClient -b <para_1> <para_2>
This invokes insertOnSessionBeforeClosed(String, String) on
TxCallerSession, which invokes TxCalledSession.insert(String) without
Connection.close().
While repeating 1 again and again results in no problem, we will
encounter the problem on the seconds,fourth and sixth execution of 2.
The source fragment of
TxCallerSessionBean.insertOnSessionBeforeClosed(String, String) is:
public void insertOnSessionBeforeClosed(String p_1, String p_2){
try{
System.out.println("Caller.insertOnSessionBeforeClosed()");
DataSource ds=(DataSource)env.lookup("jdbc/TxTest");
Connection con=ds.getConnection();
PreparedStatement stmt=con.prepareStatement("insert into tx_test
(p_1,p_2) values(?,\"no value\")");
stmt.setString(1,p_1);
stmt.executeUpdate();
stmt.close();
called.insert(p_2);
}
catch(Exception ex){
s_ctx.setRollbackOnly();
System.out.println(ex.toString());
throw (new EJBException(ex));
}
}
where 'called' is the remote reference of 'TxCalledSession'.
And that of TxCalledSessionBean.insert(String) is:
public void insert(String p){
try{
System.out.println("Called.insert()");
DataSource ds=(DataSource)env.lookup("jdbc/TxTest");
Connection con=ds.getConnection();
PreparedStatement stmt=con.prepareStatement("insert into tx_test
(p_1,p_2) values(\"no value\",?)");
stmt.setString(1,p);
stmt.executeUpdate();
stmt.close();
con.close();
}
catch(Exception ex){
s_ctx.setRollbackOnly();
System.out.println(ex.toString());
throw (new EJBException(ex));
}
}
NOTE
The difference between 1 and 2 is:
As for 1, TxCallerSessionBean.insertOnSessionAfterClosed(String, String)
invokes Connection.close() before TxCalledSessionBean.insert(String).
And TxCalledSessionBean.insert(String) invokes Connection.close() again.
As for 2, during
TxCallerSessionBean.insertOnSessionBeforeClosed(String,String),
Connection.close() is NOT invoked. Connection.close() is called only
once in TxCalledSessionBean.insert(String).
On other words:
In case of 1, Connection.close() is invoked between the two
DataSource.getConnection(). But in case of 2, the seconds
DataSource.getConnection() is invoked without Connection.close() after
the first DataSource.getConnection().
Now let's see what happens during the repetition of 2.
1. When the first execution of 2, DataSource.getConnection() in
TxCallerSessionBean.insertOnSessionBeforeClosed(String,String)
increments the value of PoolItem.open.(At this time PoolItem.open==1.)
Transaction.enlistResource(XAResource) is invoked.
2. And DataSource.getConnection() in TxCalledSessionBean.insert(String)
increments the value of PoolItem.open again.
3. So, at the time when Connection.close() (which invokes
ConnectionManager.connectionClosed()) is invoked in
TxCalledSessionBean.insert(String), the value of PoolItem.open is set to
2. During ConnectionManager.connectionClosed(),
Pool.closeConnection(XAConnection) is called at first and
Pool.closeConnection(XAConnection) decrements the value of
PoolItem.open. Now the value of PoolItem.open is 1. Within
ConnectionManager.connectionClosed(), only if PoolItem.open<1 is true,
Transaction.delistResource(XAResource,int) is invoked. This means
Transaction.delistResource(XAResource,int) is NOT invoked by
Connection.close().
4. Transaction.delistResource(XAResource,int) invokes
XAResource.end(Xid,int) and this set the boolean value of
XAResource.xa_started to false. But as long as Connection.close() does
not invoke Transaction.delistResource(XAResource,int), the boolean value
of XAResource.xa_started remains true.
5. After TxCalledSessionBean.insert(String) is finished,
Current.commit() is invoked by the container. Then
XAResource.commit(Xid,boolean) is invoked. At this point,
XAResource.commit(Xid,boolean) on the instance of XAResource whose
'xa_started' is true does not cause the serious problem. We will just
see the following message:
### commit: XA START without XA END ###
Except this message, our first execution seems to finished successfully.
6. The instance of XAConnection is put into the pool of the re-usable
XAConnection. But the instance of XAResource which is attached to such a
pooled XAConnection remains as 'started'.
7. And now let's start the second execution. Again,
DataSource.getConnection() in
TxCallerSessionBean.insertOnSessionBeforeClosed(String,String)
increments the value of PoolItem.open. Because PoolItem.open==1 is true
at this time, Transaction.enlistResource(XAResource) is invoked. This
invokes XAResource.start(Xid,int), but in this second execution,
XAResource is the one retrieved from the pool. This means the boolean
value of XAResource.xa_started is true and XAResource.start(Xid,int)
throws the exception. The failure of XAResource.start(Xid,int) also
means that the value of XAResource.currXid remains unchanged.
8. Regardless of the failure of XAResource.start(Xid,int), we can
continue our procedure. And when TxCalledSessionBean.insert(String) is
finished, Current.commit() is invoked by the container. Then
XAResource.commit(Xid,boolean) is invoked. But this throws the exception
again, because the value of XAResource.currXid does not equal to the
given Xid.
The 1-8 above also applies to the 3rd and 4th execution.
As a result, we can say:
In case that Connection.close() is called before the second
DataSource.getConnection(), there may be no problem. But if
Connection.close() is not invoked between the two
DataSource.getConnection(), we encounter the exception.
I don't know whether this restriction should be un-locked. But to unlock
this, there may be the 2 solution.
Solution 1
Both of
ConnectionManager.getConnection()
ConnectionManager.connectionClosed()
depends on the value of PoolItem.open to determine whether to invoke
Transaction.enlistResource(XAResource)
Transaction.delistResource(XAResource,int)
or not. And this results in the problem. Instead of the value of
PoolItem.open, we should use another flag which represents whether
XAResource.start(Xid,int) is invoked or not.
Solution 2
In any case, after Current.commit() is invoked, the instance of
XAResource which participated in the transaction should be marked as
'ended'.
This can be done by:
if (xa_started) {
xa_started=false;
}
within XAResource.commit(Xid,boolean) .
Which do you like? Or any of them will cause the other problem?
Any questions and comments are welcome.
PS:
I've just joined into this mailing list.
So, from now on, posting to the list is enough.
--
Happy Java programming!
Jun Inamori
E-mail: [EMAIL PROTECTED]
URL: http://www.oop-reserch.com
Mohd Faizal bin Yusof wrote:
>
> Dear all,
>
> Help please...
>
> I still get the following error message after I use the latest source from
> cvs and I also tried the patch sent by Jun Inamori but no luck. Can you help
> me interprete the error message please. The DBHelper.getConnection is just a
> static method inside a helper class that return a connection from
> datasource. Thank you in advance
>
> DBHelper.getConenction is called
> WARNING: Connection was not always closed correctly !
> DBHelper.getConenction is called
> Cannot enlist XAResource:javax.transaction.SystemException: Cannot send XA
> start
> :javax.transaction.xa.XAException: mixed transactions
> Exception in connectionClosed:javax.transaction.SystemException: Cannot send
> XA
> end:javax.transaction.xa.XAException
> DBHelper.getConenction is called
> Cannot enlist XAResource:javax.transaction.SystemException: Cannot send XA
> start
> :javax.transaction.xa.XAException: mixed transactions
> Exception in connectionClosed:javax.transaction.SystemException: Cannot send
> XA
> end:javax.transaction.xa.XAException
> Unexpected Exception on commit_one_phase:java.rmi.RemoteException:
> XAException:j
> avax.transaction.xa.XAException: Cannot mix transactions
> doPostInvoke: javax.transaction.SystemException: Unexpected Exception on
> commit_
> one_phase
>
> Faizal Yusof
> Systems Developer
> Sufficient Systems Malaysia Sdn Bhd
> Email: [EMAIL PROTECTED]
> Phone: 03-21669226
>
> -----Original Message-----
> From: Philippe Durieux [mailto:[EMAIL PROTECTED]]
> Sent: Wednesday, May 17, 2000 4:34 PM
> To: [EMAIL PROTECTED]
> Cc: [EMAIL PROTECTED]
> Subject: Re: URGENT: transaction management problem
>
> Alexandre Lefebvre wrote:
> >
> > (repost)
> >
> > From: [EMAIL PROTECTED]
> > Date: Thu, 11 May 2000 16:53:35 +0530
> >
> > Hi,
> > We are facing a serious problem regarding transaction management in
> > JOnAS2.0. It is really crucial to the completion of the project now.
> >
> > The existing application was working perfectly in J2EE. It is only after
> the
> > shift to JOnAS 2.0 that we faced this problem.
> >
> > We are using Session Beans with Transaction managed by Containers. In some
> > methods of these Beans , there is inter Bean reference, where the method
> of
> > another bean is being invoked. The invoked method of the referenced bean
> ,
> > as well as the calling method of the Calling bean have the Transaction
> > Attribute set to TX_REQUIRED.
> > If both the substituent methods are executed successfully, the data goes
> > correctly into the database, however the EJB Server still throws an
> > exception - commit_one_phase exception. As a result of which, we are not
> > able to detect the success/failure of the transaction.
> >
> > Is there a way to execute the above scenario using Bean Managed
> > Transaction(by Coding for the Transaction in the bean) ?
> >
> > Thanx!
> > Rohini
> I think this question has already been replied a few days ago, but maybe
> not in this list...
> A bug has been fixed in jonas 2.0 concerning the jdbc connections that
> were not closed by the user. In that case, you sometimes got a
> "commit_one_phase exception". Try the new JOnAS version on the cvs tree
> to see if this fix your problem.
> Another solution is to always close connections before leaving a method,
> since there is a pool of connections that is managed by the JOnAS server
> that insure that connections can be reused, i.e. the physical jdbc
> connection
> is never closed really.
>
> Philippe
> --
> Philippe Durieux ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> Bull S.A - 1 rue de Provence - 38432 Echirolles Cedex France
> [EMAIL PROTECTED] http://www-frec.bull.com
> -> Download our EJBServer at http://www.bullsoft.com/ejb <-
> ----
> This list is cross-posted to two mail lists. To unsubscribe,
> follow the instructions below for the list you subscribed to.
> For objectweb.org: send email to [EMAIL PROTECTED] and
> include in the body of the message "unsubscribe ejb-container-group".
> For enhydra.org: send email to [EMAIL PROTECTED] and include
> in the body of the message "unsubscribe ejb-container-group".
- URGENT: transaction management problem Alexandre Lefebvre
- Re: URGENT: transaction management problem Philippe Durieux
- Re: FW: URGENT: transaction management problem Jun Inamori
- Re: FW: URGENT: transaction management problem Jun Inamori
- Re: FW: URGENT: transaction management pro... Jun Inamori
S/MIME Cryptographic Signature