56 private final DataSource dataSource;
65 this.dataSource = Objects.requireNonNull(dataSource,
"dataSource");
79 try (Connection connection = dataSource.getConnection();
80 PreparedStatement statement = connection.prepareStatement(query.sql())) {
81 bind(statement, connection, query.parameters());
82 try (var resultSet = statement.executeQuery()) {
83 return extractor.
extract(resultSet);
85 }
catch (SQLException e) {
86 throw new DatabaseAccessException(
"Query failed", e);
100 public <T> List<T> queryList(
final SqlQuery query,
final RowMapper<T> mapper) {
101 return query(query, resultSet -> {
102 final List<T> result =
new ArrayList<>();
103 while (resultSet.next()) {
104 result.add(mapper.map(resultSet));
106 return List.copyOf(result);
120 public <T> Optional<T> queryOne(
final SqlQuery query,
final RowMapper<T> mapper) {
121 return query(query, resultSet -> {
122 if (!resultSet.next()) {
123 return Optional.empty();
125 final T result = mapper.map(resultSet);
126 if (resultSet.next()) {
127 throw new SQLException(
"Expected at most one row");
129 return Optional.of(result);
142 try (Connection connection = dataSource.getConnection();
143 PreparedStatement statement = connection.prepareStatement(query.sql())) {
144 bind(statement, connection, query.parameters());
146 return statement.getUpdateCount();
147 }
catch (SQLException e) {
161 public long[]
batch(
final String sql,
final List<StatementBinder> binders) {
162 try (Connection connection = dataSource.getConnection();
163 PreparedStatement statement = connection.prepareStatement(sql)) {
165 binder.bind(connection, statement);
166 statement.addBatch();
168 return statement.executeLargeBatch();
169 }
catch (SQLException e) {
184 try (Connection connection = dataSource.getConnection()) {
185 final boolean previousAutoCommit = connection.getAutoCommit();
186 connection.setAutoCommit(
false);
188 final T result = callback.
execute(connection);
190 connection.setAutoCommit(previousAutoCommit);
192 }
catch (Exception e) {
193 connection.rollback();
194 connection.setAutoCommit(previousAutoCommit);
195 throw wrap(
"Transaction failed", e);
197 }
catch (SQLException e) {
198 throw new DatabaseAccessException(
"Transaction setup failed", e);
202 private static void bind(
final PreparedStatement statement,
final Connection connection,
203 final List<SqlParameter> parameters)
throws SQLException {
204 for (
int i = 0; i < parameters.size(); i++) {
205 final SqlParameter parameter = parameters.get(i);
206 final int index = i + 1;
207 if (parameter.arrayElementType() !=
null) {
208 if (parameter.value() ==
null) {
209 statement.setNull(index, parameter.sqlType() ==
null ? java.sql.Types.ARRAY : parameter.sqlType());
211 statement.setArray(index,
212 connection.createArrayOf(parameter.arrayElementType(), (Object[]) parameter.value()));
216 if (parameter.value() ==
null) {
217 statement.setNull(index, parameter.sqlType() ==
null ? java.sql.Types.NULL : parameter.sqlType());
220 if (parameter.sqlType() !=
null) {
221 statement.setObject(index, parameter.value(), parameter.sqlType());
224 statement.setObject(index, parameter.value());
228 private static RuntimeException wrap(
final String message,
final Exception exception) {
229 return switch (exception) {
230 case RuntimeException re -> re;
231 case SQLException se ->
new DatabaseAccessException(message, se);
232 default ->
new DatabaseAccessException(message, exception);