src/main/java/com/aoindustries/dbc/Database.java
public <V,E extends Exception> V executeTransaction(
		Class<E> eClass,
		DatabaseCallableE<V,E> callable
	) throws SQLException, E {
		DatabaseConnection conn = transactionConnection.get();
		if(conn!=null) {
			// Reuse existing connection
			try {
				return callable.call(conn);
			} catch(RuntimeException err) {
				conn.rollback();
				throw err;
			} catch(NoRowException err) {
				throw err;
			} catch(SQLException err) {
				conn.rollbackAndClose();
				throw err;
			} catch(Exception e) {
				conn.rollback();
				if(eClass.isInstance(e)) throw eClass.cast(e);
				throw new SQLException(e);
			}
		} else {
			// Create new connection
			conn=createDatabaseConnection();
			try {
				transactionConnection.set(conn);
				try {
					V result = callable.call(conn);
					conn.commit();
					return result;
				} finally {
					transactionConnection.remove();
				}
			} catch(RuntimeException | NoRowException err) {
				conn.rollback();
				throw err;
			} catch(SQLException err) {
				conn.rollbackAndClose();
				throw err;
			} catch(Exception e) {
				conn.rollback();
				if(eClass.isInstance(e)) throw eClass.cast(e);
				throw new SQLException(e);
			} finally {
				conn.releaseConnection();
			}
		}
	}
public <V,E extends Exception> V executeTransaction(
		Class<E> eClass,
		DatabaseCallableE<V,E> callable
	) throws SQLException, E {
		DatabaseConnection conn = transactionConnection.get();
		if(conn!=null) {
			// Reuse existing connection
			try {
				return callable.call(conn);
			} catch(RuntimeException err) {
				conn.rollback();
				throw err;
			} catch(NoRowException err) {
				throw err;
			} catch(SQLException err) {
				conn.rollbackAndClose();
				throw err;
			} catch(Exception e) {
				conn.rollback();
				if(eClass.isInstance(e)) throw eClass.cast(e);
				throw new SQLException(e);
			}
		} else {
			// Create new connection
			conn=createDatabaseConnection();
			try {
				transactionConnection.set(conn);
				try {
					V result = callable.call(conn);
					conn.commit();
					return result;
				} finally {
					transactionConnection.remove();
				}
			} catch(RuntimeException | NoRowException err) {
				conn.rollback();
				throw err;
			} catch(SQLException err) {
				conn.rollbackAndClose();
				throw err;
			} catch(Exception e) {
				conn.rollback();
				if(eClass.isInstance(e)) throw eClass.cast(e);
				throw new SQLException(e);
			} finally {
				conn.releaseConnection();
			}
		}
	}
<p>
Executes an arbitrary transaction, providing automatic commit, rollback, and connection management.
Rolls-back the transaction on RuntimeException.
Rolls-back the transaction on NoRowException on the outer-most transaction only.
Rolls-back and closes the connection on all SQLException except NoRowException.
Rolls-back the transaction on E.
</p>
<p>
The connection allocated is stored as a ThreadLocal and will be automatically reused if
another transaction is performed within this transaction.  Any nested transaction will automatically
become part of the enclosing transaction.  For safety, a nested transaction will still rollback the
entire transaction on any exception.
</p>

@see #isInTransaction()