I haven't been following this thread closely, but with JBoss at least,
you have the option of configuring datasources as no-transaction:
no-tx-datasource. With this type of datasource, you are free to call
commit and rollback yourself. With container-managed transactions, you
should not be calling commit or rollback. I've erroneously done so, and
JBoss generates an error saying that these methods are illegal on a
container managed transaction.
Regarding your thoughts about a smart resource manager, that is indeed
what happens. Remember that datasource may be retrieved and closed any
number of times during the processing of a single EJB method. During
the execution of single EJB method, the container is required by the
spec to return the same physical connection each time getConnection() is
invoked, so that all database activity within that method (which can of
course call other methods) is guaranteed to be within the same transaction.
Only when the EJB method completes does the container do the commit or
rollback and then returns the connection to the pool as available for use.
Since iBATIS can't possible determine that it is being used in a
container-managed transaction, if you want to support that, I would
think the only possibility is to provide an optional parameter in the
data source configuration to indicate that. In such cases, iBATIS
should probably no-op commit and rollback.
On 4/19/2010 11:15 AM, Clinton Begin wrote:
Thanks Adinath.
This will all help. Let's figure this out together.
The odd thing for me is this. A typical transaction lifecycle (be it
global or otherwise would be:
* Open Connection
* Do Work
* Commit or Rollback
* Close Connection (even if this implies a return to the connection pool)
The problem with calling close on a connection that's globally managed
is that it changes the lifecycle to:
* Open Connection
* Do Work
* >> Close Connection (even if this implies a return to the connection pool)
* Commit or Rollback
Now I suppose a smart resource manager controlling the transaction would
know better than to actually return the connection to the pool until the
worker thread is finished and the transaction is either committed or
rolled back, but I'm not entirely confident that all app servers are
that smart. As you noted, glassfish doesn't even warn you when you call
commit in a managed transaction (most resource managers would throw an
exception if commit or rollback were called). I wouldn't be surprised
if this is the reason you're getting intermittent IllegalStateExceptions.
I'm going to do a little more reading tonight on JEE 6 standard behavior
to see if there's one approach we can trust.
The most empirical evidence of the proper behavior would be iBATIS 2,
which calls close. But I normally don't remove code without reason
(although it has happened ;-).
I'll check into this tonight or tomorrow at the latest.
Cheers,
Clinton
On Mon, Apr 19, 2010 at 1:26 AM, Adinath <adin...@acciente.com
<mailto:adin...@acciente.com>> wrote:
Clinton,
On Sun, Apr 18, 2010 at 2:45 PM, Clinton Begin
<clinton.be...@gmail.com <mailto:clinton.be...@gmailcom>> wrote:
You did the right thing... iBATIS transaction managers are meant
to be easy to implement yourself.
Yes, they are easy to implement!
That said, this was a matter of constant debate back in the good
old days when none of the standards were implemented
consistently. I'm still not sure if they are.
Some app servers would complain if iBATIS closed the connection,
because if some downstream process needed a connection,
theoretically it was supposed to use the same one (which would
be closed by that time). I think the trick is to ensure that
you're using a container managed DataSource. Are you retrieving
a DataSource configured by GlassFish from a JNDI context (in
other words, a container manged DataSource)? Or are you just
using the iBATIS built-in SimpleDataSource?
Yes I am using using a container managed datasource (GlassFish v3
managing a DB2 v9.7 connection), looked up via JNDI. I create the
iBATIS session factory using SqlSessionFactoryBuilder and the
related classes (i.e. no XML config file).
I
I would expect a container managed DataSource to lazily
initialize a connection for any one worker thread, and continue
to provide that same connection to any requester for that
particular DataSource. Then I'd expect it to close that
connection at the end of the entire workflow.
My experience with GlassFish is that the connection needs to be
closed to be returned to the pool.
With GlassFish I wrote a set of tests and established that if you
call commit() on a JDBC connection returned by the container managed
datasource it causes an commit (thru to the driver), defeating the
EJB transaction.
There are 2 other issues I ommitted in my original post, for
clarity. I suspect these 2 issues have nothing to do with IBATIS,
but I am just sharing FYI (just in case).
*Issue #1*
In the close() method of my custom iBATIS transaction class I would
transiently (about every 4 times) get IllegalStateException with
"state.isBusy() : false" in the message when I call
connection.close(). Some posts pointed that this happens when the
connection is already closed. But I have verified using the debugger
that this does not apply, the connection is open and isClosed()
returns false. The fix for now is to catch the IllegalStateException
the close() and ignore it! :(
*Issue #2*
The other issue is rather unnerving, I am reluctant to share it
since it is a little winded, but thought perhaps it may help someone
else. This too I suspect has nothing to do with iBATIS. It is as
follows:
- there is a stateful session bean (sfsb) A that has a reference to
another sfsb B
- there is a method in sfsb A, say methodOfA, which inserts a row
using iBATIS
- there is a method in sfsb B, say methodOfB, which inserts a row
using direct JDBC
- methodOfB() also uses a container managed DataSource to
retrieve a connection and does connection.close() before returning
- now the logic in methodOfA() looks like below:
public void methodOfA()
{
session = sessionFactory.openSession()
boolean commit = false;
try
{
mapper = session.getMapper( UserMapper.class);
someID = beanB.methodOfB();
// set value for user
user = new User();
user.setOtherStuff() ...
user.setSomeID( someID );
// insert row for new user
mapper.insertUser( user );
commit = true;
}
finally
{
sessionclose();
if ( ! commit )
{
sessionCtx.setRollbackOnly();
}
}
}
The issue here is that if I set a debug breakpoint at the line with
mapper.insertUser( user ),I sometimes see the update by
referenceToB.methodInB() get commited to the database!! (checked via
a DB2 SQL console) This happened late Friday and I have not had a
chance to look at since. I think the culprit here is GlassFish, I
suspect that this happens only during debugging (need to verify this).
On a final note, I have used iBATIS 2 on a previous project and
iBATIS 3 on the current one. Even with IBATIS 2 I thought it was an
incredible piece of work, well-thought out and a pleasure to use.
Especially love the support for dynamic SQL, and the type handler
callbacks. Excellent work!
Best,
Adi
--
Acciente, LLC
Systems Architecture and Software Design
www.acciente.com <http://www.acciente.com>
www.inductionframework.org <http://www.inductionframework.org>
--
Guy Rouillier
---------------------------------------------------------------------
To unsubscribe, e-mail: user-java-unsubscr...@ibatis.apache.org
For additional commands, e-mail: user-java-h...@ibatis.apache.org