Skip to content

Commit

Permalink
Add javadoc
Browse files Browse the repository at this point in the history
  • Loading branch information
kaklakariada committed Oct 13, 2024
1 parent 5be5751 commit 9c25e22
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 22 deletions.
22 changes: 11 additions & 11 deletions src/main/java/org/itsallcode/jdbc/BatchInsert.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,24 @@ void add(final T row) {
}
}

@Override
public void close() {
executeBatch();
LOG.fine(() -> "Batch insert of %d rows with batch size %d completed in %s".formatted(rows, maxBatchSize,
Duration.between(start, Instant.now())));
statement.close();
}

private void executeBatch() {
if (currentBatchSize == 0) {
LOG.finest("No rows added to batch, skip");
return;
}
final Instant batchStart = Instant.now();
statement.executeBatch();
final int[] result = statement.executeBatch();
final Duration duration = Duration.between(batchStart, Instant.now());
LOG.finest(() -> "Execute batch of " + currentBatchSize + " after " + rows + " took " + duration.toMillis()
+ " ms");
LOG.finest(() -> "Execute batch of %d after %d took %d ms, result length: %s".formatted(currentBatchSize, rows,
duration.toMillis(), result.length));
currentBatchSize = 0;
}

@Override
public void close() {
executeBatch();
LOG.fine(() -> "Batch insert of %d rows with batch size %d completed in %s".formatted(rows, maxBatchSize,
Duration.between(start, Instant.now())));
statement.close();
}
}
44 changes: 44 additions & 0 deletions src/main/java/org/itsallcode/jdbc/BatchInsertBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

/**
* Builder for batch inserts.
*
* @param <T> row type
*/
public class BatchInsertBuilder<T> {
private static final Logger LOG = Logger.getLogger(BatchInsertBuilder.class.getName());
Expand All @@ -27,23 +29,49 @@ public class BatchInsertBuilder<T> {
this.context = context;
}

/**
* Define table and column names used for generating the {@code INSERT}
* statement.
*
* @param tableName table name
* @param columnNames column names
* @return {@code this} for fluent programming
*/
@SuppressWarnings("java:S3242") // Using List instead of Collection to preserve column order
public BatchInsertBuilder<T> into(final String tableName, final List<String> columnNames) {
this.sql = createInsertStatement(Identifier.simple(tableName),
columnNames.stream().map(Identifier::simple).toList());
return this;
}

/**
* Define {@link Stream} of rows to insert.
*
* @param rows rows to insert
* @return {@code this} for fluent programming
*/
public BatchInsertBuilder<T> rows(final Stream<T> rows) {
final Iterator<T> iterator = rows.iterator();
return rows(iterator);
}

/**
* Define {@link Iterator} of rows to insert.
*
* @param rows rows to insert
* @return {@code this} for fluent programming
*/
public BatchInsertBuilder<T> rows(final Iterator<T> rows) {
this.rows = rows;
return this;
}

/**
* Define mapping how rows are converted to {@code Object[]} for inserting.
*
* @param rowMapper row mapper
* @return {@code this} for fluent programming
*/
public BatchInsertBuilder<T> mapping(final ParamConverter<T> rowMapper) {
final RowPreparedStatementSetter<Object[]> setter = new ObjectArrayPreparedStatementSetter(
context.getParameterMapper());
Expand All @@ -52,11 +80,24 @@ public BatchInsertBuilder<T> mapping(final ParamConverter<T> rowMapper) {
preparedStatement));
}

/**
* Define {@link RowPreparedStatementSetter} that sets values of a
* {@link PreparedStatement} for each row.
*
* @param preparedStatementSetter prepared statement setter
* @return {@code this} for fluent programming
*/
public BatchInsertBuilder<T> mapping(final RowPreparedStatementSetter<T> preparedStatementSetter) {
this.mapper = preparedStatementSetter;
return this;
}

/**
* Define maximum batch size, using {@link #DEFAULT_MAX_BATCH_SIZE} as default.
*
* @param maxBatchSize maximum batch size
* @return {@code this} for fluent programming
*/
public BatchInsertBuilder<T> maxBatchSize(final int maxBatchSize) {
this.maxBatchSize = maxBatchSize;
return this;
Expand All @@ -68,6 +109,9 @@ private static String createInsertStatement(final Identifier table, final List<I
return "insert into " + table.quote() + " (" + columns + ") values (" + placeholders + ")";
}

/**
* Start the batch insert process.
*/
public void start() {
Objects.requireNonNull(this.sql, "sql");
Objects.requireNonNull(this.mapper, "mapper");
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/itsallcode/jdbc/ParamConverter.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package org.itsallcode.jdbc;

/**
* This converts a domain object to types supported by the database when
* inserting rows.
* This converts a domain object to an array of types supported by the database
* when inserting rows.
*
* @param <T> row type
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ void setValues(final PreparedStatementSetter preparedStatementSetter) {

}

void executeBatch() {
int[] executeBatch() {
try {
statement.executeBatch();
return statement.executeBatch();
} catch (final SQLException e) {
throw new UncheckedSQLException("Error executing batch sql '" + sql + "'", e);
}
Expand Down
21 changes: 14 additions & 7 deletions src/test/java/org/itsallcode/jdbc/ExampleTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
import java.util.stream.Stream;

Expand All @@ -13,19 +15,24 @@
import org.junit.jupiter.api.Test;

class ExampleTest {
record Name(int id, String name) {
static void setPreparedStatement(final Name row, final PreparedStatement stmt) throws SQLException {
stmt.setInt(1, row.id);
stmt.setString(2, row.name);
}
}

@Test
void example() {
record Name(int id, String name) {
Object[] toRow() {
return new Object[] { id, name };
}
}
final ConnectionFactory connectionFactory = ConnectionFactory
.create(Context.builder().build());
try (SimpleConnection connection = connectionFactory.create("jdbc:h2:mem:", "user", "password")) {
connection.executeScript(readResource("/schema.sql"));
connection.batchInsert(Name.class).into("NAMES", List.of("ID", "NAME"))
.rows(Stream.of(new Name(1, "a"), new Name(2, "b"), new Name(3, "c"))).mapping(Name::toRow).start();
connection.batchInsert(Name.class)
.into("NAMES", List.of("ID", "NAME"))
.rows(Stream.of(new Name(1, "a"), new Name(2, "b"), new Name(3, "c")))
.mapping(Name::setPreparedStatement)
.start();

try (SimpleResultSet<Row> rs = connection.query("select * from names order by id")) {
final List<Row> result = rs.stream().toList();
Expand Down

0 comments on commit 9c25e22

Please sign in to comment.