org.codefilarete.tool.sql.TransactionSupport Maven / Gradle / Ivy
package org.codefilarete.tool.sql;
import java.sql.Connection;
import java.sql.SQLException;
import org.codefilarete.tool.function.ThrowingConsumer;
import org.codefilarete.tool.function.ThrowingFunction;
/**
* Class aimed at easing to create, commit and rollback a SQL Transaction
*
* @author Guillaume Mary
*/
public class TransactionSupport {
/**
* Simple method to apply any sql order (through a {@link Connection} {@link java.util.function.Consumer}) within a transaction.
* Statements must be created by the {@link java.util.function.Consumer} from the {@link Connection}, if they are created outside then
* behavior is unknown (can't find any information about calling {@link Connection#createStatement()} before disabling commit and then
* executing statement).
*
* @param connectionConsumer a sql order cerator and executor
* @param connection the connection that will manage the transaction (will by given to {@link java.util.function.Consumer} as argument)
* @throws SQLException any error thrown during connection interaction
*/
public static void runAtomically(ThrowingConsumer connectionConsumer, Connection connection) throws SQLException {
new TransactionSupport(connection)
.runAtomically(connectionConsumer);
}
/**
* Simple method to apply any sql order (through a {@link Connection} {@link java.util.function.Function}) within a transaction.
* Statements must be created by the {@link java.util.function.Function} from the {@link Connection}, if they are created outside then
* behavior is unknown (can't find any information about calling {@link Connection#createStatement()} before disabling commit and then
* executing statement).
*
* @param connectionConsumer a sql order cerator and executor
* @param connection the connection that will manage the transaction (will by given to {@link java.util.function.Consumer} as argument)
* @return connectionConsumer result
* @throws SQLException any error thrown during connection interaction
*/
public static T runAtomically(ThrowingFunction connectionConsumer, Connection connection) throws SQLException {
return new TransactionSupport(connection)
.runAtomically(connectionConsumer);
}
/** Transaction identifier. For logging or any other tracing process */
private final String transactionId;
private final Connection connection;
private boolean wasAutoCommit;
public TransactionSupport(Connection connection) {
this.connection = connection;
// in a non JVM-shared, an Hexa String of the hashCode is sufficient as id
transactionId = Integer.toHexString(hashCode());
}
public String getId() {
return transactionId;
}
public TransactionSupport begin() throws SQLException {
// remember previous commit mode to set it back further
wasAutoCommit = connection.getAutoCommit();
if (wasAutoCommit) {
connection.setAutoCommit(false);
}
return this;
}
public void commit() throws SQLException {
connection.commit();
}
public void rollback() throws SQLException {
connection.rollback();
}
public TransactionSupport end() throws SQLException {
// set commit state back
if (wasAutoCommit) {
connection.setAutoCommit(true);
}
return this;
}
/**
* Will execute any sql order (through a {@link Connection} {@link java.util.function.Consumer}) within a transaction.
*
* @param connectionConsumer a sql order cerator and executor
* @throws SQLException any error thrown during connection interaction
*/
public void runAtomically(ThrowingConsumer connectionConsumer) throws SQLException {
runAtomically((ThrowingFunction) connection -> {
connectionConsumer.accept(connection);
return null;
});
}
/**
* Will execute any sql order (through a {@link Connection} {@link java.util.function.Consumer}) within a transaction and return result built
* by given {@link java.util.function.Function}.
*
* @param connectionConsumer a sql order cerator and executor
* @return connectionConsumer result
* @throws SQLException any error thrown during connection interaction
*/
public T runAtomically(ThrowingFunction connectionConsumer) throws SQLException {
begin();
try {
T result = connectionConsumer.apply(connection);
commit();
return result;
} catch (SQLException e) {
try {
rollback();
} catch (SQLException e1) {
e.addSuppressed(e1);
}
throw e;
} finally {
end();
}
}
}