JDBCTransaction.java
/***************************************************************************
Copyright 2009 Emily Estes
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
***************************************************************************/
package net.metanotion.util;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import net.metanotion.functor.Block;
/** This evaluates a block inside a JDBC trasnsaction, commiting the transaction if no exception is thrown, rolling
back the transaction otherwise. Essentially, given a connection pool({@link javax.sql.DataSource}), this class does the
following:
<ol>
<li>Acquire a connection from the DataSource</li>
<li>Start a SQL transaction: Connection.setAutoCommit(false);</li>
<li>Evaluate a block against the connection: return Block.eval(connection);</li>
<li>If an exception is thrown, rollback the transaction: Connection.rollback();</li>
<li> Finally, commit the transaction and close the connection: Connection.setAutoCommit(true);</li>
</ol> */
public final class JDBCTransaction {
/** Take a connection and block, and execute the block on the connection in a transactional context.
@param <I> The type of the value returned by this transaction.
@param conn The SQL database connection to use.
@param block The block evaluate in the context of a SQL transaction against conn.
@return The result of evaluating the block.
@throws RuntimeException if the transaction was rolled back wrapping the exception that the block threw.
*/
public static <I> I doTX(final Connection conn, final Block<Connection,I> block) {
try {
conn.setAutoCommit(false);
return block.eval(conn);
} catch (final Exception e) {
try {
conn.rollback();
} catch (final SQLException sqle2) { throw new RuntimeException(sqle2); }
throw new RuntimeException(e);
} finally {
try {
conn.setAutoCommit(true);
} catch (final SQLException sqle3) { throw new RuntimeException(sqle3); }
}
}
/** Acquire a connection from a datasource, and evaluate the block within a SQL transaction, closing the
connection when we're done.
@param <I> The type of the value returned by this transaction.
@param ds The data source to acquire the connection from.
@param block The block to evaluate against the connection.
@return The result of evaluating the block.
@throws RuntimeException if the transaction was rolled back wrapping the exception that the block threw.
*/
public static <I> I doTX(final DataSource ds, final Block<Connection,I> block) {
try (final Connection conn = ds.getConnection()) {
return doTX(conn, block);
} catch (final SQLException sqle) { throw new RuntimeException(sqle); }
}
}