Some robustness bits.
It's not clear what the right thing to do is if the database connection fails
during the middle of a transaction. In general, one can't talk to the database
after that, so I'm assuming the transaction is aborted (or eventually aborted)
and rolled back, and everything has to be retried.
I'm not currently tracking state inside a Transaction, which means that I don't
freak out if you call commit() then call rollback(), I just ignore the latter
call, and it's also possible to do something stupid like:
Transaction tx = Transaction.start(ctx);
try {
_somRepo.doOp(..);
} catch (DatabaseException de) {
// no problem!, keep on keepin' on
}
_someRepo.doAnotherOp(...);
tx.commit();
If the first repo op fails due to a database connection failure, the
transaction will get a new database connection for the second op and do the
last half of the op in a new connection.
I guess I'll have to do some state tracking, because stupid as the above code
is, I'm sure some circumstance will arise where it seems like a reasonable
thing to do, and hilarity will ensue. Blah.
This commit is contained in:
@@ -585,8 +585,16 @@ public class PersistenceContext
|
||||
checkAreInitialized(); // le check du sanity
|
||||
|
||||
boolean isReadOnly = op.isReadOnly();
|
||||
ConnOp connop;
|
||||
Transaction tx = Transaction.get();
|
||||
ConnOp connop = (tx == null) ? new NonTxOp(isReadOnly) : new TxOp(tx);
|
||||
if (tx != null) {
|
||||
if (tx.ctx != this) throw new IllegalStateException(
|
||||
"Cannot perform database ops on multiple persistence contexts in a transaction " +
|
||||
"[txCtx=" + tx.ctx._ident + ", thisCtx=" + _ident + "].");
|
||||
connop = new TxOp(tx);
|
||||
} else {
|
||||
connop = new NonTxOp(isReadOnly);
|
||||
}
|
||||
|
||||
long preConnect = System.nanoTime();
|
||||
Connection conn;
|
||||
|
||||
@@ -92,20 +92,26 @@ public class Transaction {
|
||||
}
|
||||
}
|
||||
|
||||
/** The persistence context in which this transaction is operating. */
|
||||
public final PersistenceContext ctx;
|
||||
|
||||
/**
|
||||
* Commits this transaction.
|
||||
*/
|
||||
public void commit ()
|
||||
{
|
||||
if (_conn != null) {
|
||||
checkActive("commit");
|
||||
try {
|
||||
checkActive("commit");
|
||||
try {
|
||||
if (_conn != null) {
|
||||
_conn.commit();
|
||||
} catch (SQLException sqe) {
|
||||
throw new DatabaseException("Transaction commit failure", sqe);
|
||||
} finally {
|
||||
release();
|
||||
ctx._conprov.releaseTxConnection(ctx._ident, _conn);
|
||||
}
|
||||
} catch (SQLException sqe) {
|
||||
throw new DatabaseException("Transaction commit failure", sqe);
|
||||
connectionFailed(sqe);
|
||||
} finally {
|
||||
_conn = null;
|
||||
_activeTx.set(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,23 +120,22 @@ public class Transaction {
|
||||
*/
|
||||
public void rollback ()
|
||||
{
|
||||
if (_conn != null) {
|
||||
checkActive("rollback");
|
||||
try {
|
||||
try {
|
||||
if (_conn != null) {
|
||||
checkActive("rollback");
|
||||
_conn.rollback();
|
||||
} catch (SQLException sqe) {
|
||||
throw new DatabaseException("Transaction rollback failure", sqe);
|
||||
} finally {
|
||||
release();
|
||||
ctx._conprov.releaseTxConnection(ctx._ident, _conn);
|
||||
}
|
||||
} catch (SQLException sqe) {
|
||||
throw new DatabaseException("Transaction rollback failure", sqe);
|
||||
connectionFailed(sqe);
|
||||
} finally {
|
||||
_conn = null;
|
||||
_activeTx.set(null);
|
||||
}
|
||||
}
|
||||
|
||||
/** The persistence context in which this transaction is operating. */
|
||||
public final PersistenceContext ctx;
|
||||
|
||||
Connection getConnection ()
|
||||
throws PersistenceException
|
||||
Connection getConnection () throws PersistenceException
|
||||
{
|
||||
if (_conn == null) _conn = ctx._conprov.getTxConnection(ctx._ident);
|
||||
return _conn;
|
||||
@@ -151,12 +156,6 @@ public class Transaction {
|
||||
"Attempted to " + action + " non-active transaction");
|
||||
}
|
||||
|
||||
protected void release () {
|
||||
ctx._conprov.releaseTxConnection(ctx._ident, _conn);
|
||||
_conn = null;
|
||||
_activeTx.set(null);
|
||||
}
|
||||
|
||||
protected static final ThreadLocal<Transaction> _activeTx = new ThreadLocal<Transaction>();
|
||||
|
||||
/** The connection being used for this transaction. */
|
||||
|
||||
Reference in New Issue
Block a user