I would not say that setAutoCommit(true) removes you from the
context of a transaction. You'll get a new transaction for every action,
and they're committed without your intervention. That is, if you're in
*no* transaction, and you do some work, and then close your client and
restart the DB, the state of the data is not well defined (to my
knowledge). Some DBs may commit, some may roll back, some may just
complain. If you turn on auto-commit, the behavior is different - it
behaves exactly like there's a new transaction for every statement and you
commit after every statement, so any work you do is guaranteed to be
applied - see what I mean?
Now, I agree that the behavior is different between JDBC 1/2 and
the JSBC 2 Optional Package. But everyone who's using EJBs kind of has
the Optional Package behavior thrust upon them, so that's the problem we
need to solve.
So, the server code required to attach a new transaction to an
old connection is fairly straightforward. But I don't believe we can
determine *when to do that*. I don't believe that every DB connection
that is not part of a transaction should be attached whenever a new
transaction is started. Even if we tried to map connections to threads or
something, I don't believe that every DB connection used in one particular
place should be automatically attached to a transaction when a new
transactions is started. Isn't the whole point of client/bean-demarcated
transactions that the developer handles the mechanics of the transaction,
so shouldn't they be the one to decide which connections go with which
transactions?
Unfortunately, there is no way for the developer to do
that. Though the server code is trivial, the bean code is not possible -
not without excessive casting and digging through internal server clases,
which would be a *major* no-no. There are no methods of Connection or
UserTransaction or Transaction that would allow a developer to make this
association.
So, it seems to be we have 3 options:
1) Force all connections to be associated with a new transaction, so the
only way to have a connection associated with no transaction is to have no
transaction.
2) Force you to open and close a connection within opening and closing a
transaction to associate them, and open a connection outside opening and
closing a transaction to use a connection associated with no transaction.
3) If you open a connection between opening and closing a transaction, it
is associated with the transaction until the transaction is committed or
rolled back; thereafter it is associated with no transaction until it is
closed. If you open a connection before opening a transaction, it is
always associated with no transaction.
I prefer option 2, because you have flexibility on whether your
connections are associated with a transaction or not, and consistency in
that a conneciton is either associated or not, but does not change over
its lifetime.
Aaron
On Wed, 20 Sep 2000, Charles Crain wrote:
> Ahh yes, I see your point. However, keep in mind that if you are just
> making
> JDBC calls (not using JTA or anything), you can do multiple transactions
> for
> one connection like this:
>
> jdbcConn.setAutoCommit(false);
> jdbcConn.doSomeStuff();
> jdbcConn.doSomeMoreStuff();
> jdbcConn.commit();
> jdbcConn.doSomeStuff();
> jdbcConn.doSomeMoreStuff();
> jdbcConn.rollback();
> jdbcConn.setAutoCommit(true);
> jdbcConn.doSomeStuffOutsideTransaction();
> jdbcConn.setAutoCommit(false);
> jdbcConn.inTheTransactionAgain();
> ...
>
> Actually, looking at the above, I see I may have answered your first
> question
> somewhat misleadingly (the one about transactions going away when you
> commit()). The semantics of UserTransaction say that yes, a transaction
> goes
> away when you commit() or rollback() it. After a call to either of
> these
> methods, you are now operating outside a transaction.
>
> HOWEVER, in JDBC, the semantics are different, since there is no call to
> begin(). When you call setAutoCommit(false), that means that ALL
> FURTHER
> CALLS on that connection are in a transactional scope. A call to
> commit() or
> rollback() ends the first transaction and immediately starts a new one.
> The
> only way to get out of transactional scope is to say
> setAutoCommit(true).
>
> So one has the difficult task of mapping the UserTransaction semantics
> (begin(), commit()/rollback()) to JDBC semantics (setAutoCommit(false),
> commit()/rollback(), setAutoCommit(true)). However, I see the problem
> of
> beginning a transaction on an already open connection. That would
> somehow
> require propagating the call to UserTransaction::begin() all the way
> down to
> the already-open JDBC connection, which would cause a call to
> setAutoCommit(false). I haven't look at this portion of the code, so I
> don't
> know what is involved...I assume there will be some fooling with the XA
> classes.
>
> Let me know what you think.
>
> -Charles
>
> Aaron Mulder wrote:
>
> > On Tue, 19 Sep 2000, Charles Crain wrote:
> > > My feeling on that is that anything goes with client- and
> > > bean-demarcated transactions. Let's for a second (to simplify things)
> > > imagine Minerva doesn't exist (no offense Aaron) and say we are just
> > > connecting to JDBC directly. I can certainly envision starting a
> > > transaction, doing some work, committing it, then doing some work
> > > outside a transaction (probably some queries), then opening a second
> > > transaction, do some work, then roll it back or commit it. The issue
> > > of committing after closing a direct JDBC connection doesn't apply of
> > > course, because you can't do that.
> >
> > You can't do this in a transactional environment, as far as I can
> > tell. Let's say you open a transaction, open a connection, do some work,
> > commit. Now the transaction is gone. Do some queries, open another
> > transaction. Your existing connection is not associated with that new
> > transaction. There is, as far as I can tell, no way for you to tell a
> > transaction that you want it to associate with an existing connection
> > (javax.transaction.UserTransaction seems pretty bare). And the server
> > can't do it automatically, because you could create three new
> > transactions, and then which one would it pick?
> > So the only way for you to do this is to get a second connection
> > after you started the second transaction, and then is there a compelling
> > reason not to do it the way I proposed?
> >
> > Aaron
> >
> > >
> > > If possible, this sort of thing should be allowed by Minerva in my
> > > opinion. I agree with Aaron that it's probably tighter design on the
> > > part of the bean programmer not to be doing all kinds of junk like
> > > this, but the spec does allow for it.
> > >
> > > I don't think it's in anyway a huge deal if we don't support this, if
> > > it is a difficult fix. However, if we decide not to support it, we
> > > should be very explicit about it, such that if a user gets an error
> > > due to this non-standard behavior on our part.
> > >
> > > -Charles
>