com.github.kagkarlsson.jdbc.JdbcRunner Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of micro-jdbc Show documentation
Show all versions of micro-jdbc Show documentation
Simple low-level helpers for jdbc-access
/**
* Copyright (C) Gustav Karlsson
*
* 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 com.github.kagkarlsson.jdbc;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.sql.DataSource;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
public class JdbcRunner {
private static final Logger LOG = LoggerFactory.getLogger(JdbcRunner.class);
private final ConnectionSupplier connectionSupplier;
public JdbcRunner(DataSource dataSource) {
this(dataSource, false);
}
public JdbcRunner(DataSource dataSource, boolean commitWhenAutocommitDisabled) {
this(new ConnectionSupplier() {
@Override
public Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
@Override
public boolean commitWhenAutocommitDisabled() {
return commitWhenAutocommitDisabled;
}
});
}
public JdbcRunner(ConnectionSupplier connectionSupplier) {
this.connectionSupplier = connectionSupplier;
}
public int execute(String query, PreparedStatementSetter setParameters) {
return execute(query, setParameters, Statement::getUpdateCount);
}
public List query(String query, PreparedStatementSetter setParameters, RowMapper rowMapper) {
return execute(query, setParameters, (PreparedStatement p) -> mapResultSet(p, rowMapper));
}
public T query(String query, PreparedStatementSetter setParameters, ResultSetMapper resultSetMapper) {
return execute(query, setParameters, (PreparedStatement p) -> mapResultSet(p, resultSetMapper));
}
private T execute(String query, PreparedStatementSetter setParameters, AfterExecution afterExecution) {
return withConnection(c -> {
PreparedStatement preparedStatement = null;
try {
try {
preparedStatement = c.prepareStatement(query);
} catch (SQLException e) {
throw new SQLRuntimeException("Error when preparing statement.", e);
}
try {
LOG.trace("Setting parameters of prepared statement.");
setParameters.setParameters(preparedStatement);
} catch (SQLException e) {
throw new SQLRuntimeException(e);
}
try {
LOG.trace("Executing prepared statement");
preparedStatement.execute();
T returnValue = afterExecution.doAfterExecution(preparedStatement);
commitIfNecessary(c);
return returnValue;
} catch (SQLException e) {
rollbackIfNecessary(c);
throw translateException(e);
}
} finally {
nonThrowingClose(preparedStatement);
}
});
}
private void commitIfNecessary(Connection c) {
try {
if (connectionSupplier.commitWhenAutocommitDisabled() && !c.getAutoCommit()) {
c.commit();
}
} catch (SQLException e) {
throw new SQLRuntimeException("Failed to commit.", e);
}
}
private void rollbackIfNecessary(Connection c) {
try {
if (connectionSupplier.commitWhenAutocommitDisabled() && !c.getAutoCommit()) {
c.rollback();
}
} catch (SQLException e) {
throw new SQLRuntimeException("Failed to rollback.", e);
}
}
private SQLRuntimeException translateException(SQLException ex) {
if (ex instanceof SQLIntegrityConstraintViolationException) {
return new IntegrityConstraintViolation(ex);
} else {
return new SQLRuntimeException(ex);
}
}
private T withConnection(Function doWithConnection) {
Connection c;
try {
LOG.trace("Getting connection from datasource");
c = connectionSupplier.getConnection();
} catch (SQLException e) {
throw new SQLRuntimeException("Unable to open connection", e);
}
try {
return doWithConnection.apply(c);
} finally {
nonThrowingClose(c);
}
}
private List mapResultSet(PreparedStatement executedPreparedStatement, RowMapper rowMapper) {
return withResultSet(
executedPreparedStatement,
(ResultSet rs) -> {
List results = new ArrayList<>();
while (rs.next()) {
results.add(rowMapper.map(rs));
}
return results;
});
}
private T mapResultSet(PreparedStatement executedPreparedStatement, ResultSetMapper resultSetMapper) {
return withResultSet(
executedPreparedStatement,
(ResultSet rs) -> resultSetMapper.map(rs)
);
}
private T withResultSet(PreparedStatement executedPreparedStatement, DoWithResultSet doWithResultSet) {
ResultSet rs = null;
try {
try {
rs = executedPreparedStatement.getResultSet();
} catch (SQLException e) {
throw new SQLRuntimeException(e);
}
try {
return doWithResultSet.withResultSet(rs);
} catch (SQLException e) {
throw new SQLRuntimeException(e);
}
} finally {
nonThrowingClose(rs);
}
}
private void nonThrowingClose(AutoCloseable toClose) {
if (toClose == null) {
return;
}
try {
LOG.trace("Closing " + toClose.getClass().getSimpleName());
toClose.close();
} catch (Exception e) {
LOG.warn("Exception on close of " + toClose.getClass().getSimpleName(), e);
}
}
interface AfterExecution {
T doAfterExecution(PreparedStatement executedPreparedStatement) throws SQLException;
}
interface DoWithResultSet {
T withResultSet(ResultSet rs) throws SQLException;
}
}