Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [PR #44](https://github.com/itsallcode/simple-jdbc/pull/44): Add `GenericDialect` for unsupported databases
- [PR #45](https://github.com/itsallcode/simple-jdbc/pull/45): Rename `executeStatement()` to `executeUpdate()` and return row count (**Breaking change**)
- [PR #46](https://github.com/itsallcode/simple-jdbc/pull/46): Close `Statement` / `PreparedStatement` when closing the result set.
- [PR #47](https://github.com/itsallcode/simple-jdbc/pull/47): Rename `BatchInsert` to `PreparedStatementBatch`, allow specifying a custom SQL statement (**Breaking change**)

## [0.9.0] - 2024-12-23

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ See complete example code in [ExampleTest](src/test/java/org/itsallcode/jdbc/exa
import org.itsallcode.jdbc.ConnectionFactory;
import org.itsallcode.jdbc.SimpleConnection;
import org.itsallcode.jdbc.Transaction;
import org.itsallcode.jdbc.resultset.batch.BatchInsert;
import org.itsallcode.jdbc.resultset.batch.StatementBatch;
import org.itsallcode.jdbc.resultset.SimpleResultSet;
import org.itsallcode.jdbc.resultset.generic.Row;
```
Expand Down Expand Up @@ -93,7 +93,7 @@ connection.batchInsert(Name.class)
This allows using batch inserts without creating objects for each row to avoid memory allocations.

```java
try (BatchInsert batch = transaction.batchInsert().into("NAMES", List.of("ID", "NAME")).build()) {
try (PreparedStatementBatch batch = transaction.preparedStatementBatch().into("NAMES", List.of("ID", "NAME")).build()) {
for (int i = 0; i < 5; i++) {
final int id = i + 1;
batch.add(ps -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
@ExtendWith(MockitoExtension.class)
class BatchInsertPerformanceTest {
private static final int ROW_COUNT = 10_000_000;
private static final int MAX_BATCH_SIZE = BatchInsertBuilder.DEFAULT_MAX_BATCH_SIZE;
private static final int MAX_BATCH_SIZE = PreparedStatementBatchBuilder.DEFAULT_MAX_BATCH_SIZE;
@Mock
SimpleConnection connectionMock;
@Mock
Expand All @@ -35,12 +35,12 @@ void rowStatementSetter() {
}).rows(generateStream(ROW_COUNT)).start();
}

private RowBatchInsertBuilder<NameRow> rowTestee() {
return new RowBatchInsertBuilder<NameRow>(this::prepareStatement).maxBatchSize(MAX_BATCH_SIZE);
private RowPreparedStatementBatchBuilder<NameRow> rowTestee() {
return new RowPreparedStatementBatchBuilder<NameRow>(this::prepareStatement).maxBatchSize(MAX_BATCH_SIZE);
}

private BatchInsertBuilder testee() {
return new BatchInsertBuilder(this::prepareStatement).maxBatchSize(MAX_BATCH_SIZE);
private PreparedStatementBatchBuilder testee() {
return new PreparedStatementBatchBuilder(this::prepareStatement).maxBatchSize(MAX_BATCH_SIZE);
}

private SimplePreparedStatement prepareStatement(final String sql) {
Expand Down Expand Up @@ -75,7 +75,7 @@ void objectArray() {
@Test
@Timeout(value = 10, unit = TimeUnit.SECONDS)
void directAdd() {
try (BatchInsert batch = testee().into("TEST", List.of("ID", "NAME")).build()) {
try (PreparedStatementBatch batch = testee().into("TEST", List.of("ID", "NAME")).build()) {
for (int i = 0; i < ROW_COUNT; i++) {
final int row = i;
batch.add(ps -> {
Expand All @@ -89,7 +89,7 @@ void directAdd() {
@Test
@Timeout(value = 10, unit = TimeUnit.SECONDS)
void directAddBatch() throws SQLException {
try (BatchInsert batch = testee().into("TEST", List.of("ID", "NAME")).build()) {
try (PreparedStatementBatch batch = testee().into("TEST", List.of("ID", "NAME")).build()) {
final PreparedStatement statement = batch.getStatement();
for (int i = 0; i < ROW_COUNT; i++) {
statement.setInt(1, i);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ void batchInsert() {
try (final SimpleConnection connection = connect()) {
connection.executeUpdate("create schema test");
connection.executeUpdate("create table tab(col date)");
connection.batchInsert(LocalDate.class).into("TAB", List.of("COL"))
connection.preparedStatementBatch(LocalDate.class).into("TAB", List.of("COL"))
.mapping((row, stmt) -> stmt.setObject(1, row)).rows(Stream.of(date)).start();
try (SimpleResultSet<LocalDate> resultSet = connection.query("select * from tab",
(rs, rowNum) -> rs.getObject(1, LocalDate.class))) {
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
* <li>... with a prepared statement and custom parameter setter:
* {@link org.itsallcode.jdbc.DbOperations#executeUpdate(String, org.itsallcode.jdbc.PreparedStatementSetter)}</li>
* <li>... multiple statements in a batch:
* {@link org.itsallcode.jdbc.DbOperations#batch()}</li>
* {@link org.itsallcode.jdbc.DbOperations#statementBatch()}</li>
*
* <li>... semicolon separated SQL script:
* {@link org.itsallcode.jdbc.DbOperations#executeScript(String)}</li>
Expand Down Expand Up @@ -57,9 +57,9 @@
* <ul>
* <li>... using a {@link java.util.stream.Stream} or {@link java.util.Iterator}
* of row objects:
* {@link org.itsallcode.jdbc.SimpleConnection#batchInsert(java.lang.Class)}</li>
* {@link org.itsallcode.jdbc.SimpleConnection#preparedStatementBatch(java.lang.Class)}</li>
* <li>... directly setting values of a {@link java.sql.PreparedStatement}:
* {@link org.itsallcode.jdbc.SimpleConnection#batchInsert()}</li>
* {@link org.itsallcode.jdbc.SimpleConnection#preparedStatementBatch()}</li>
* </ul>
* </li>
* <li>Simplified Exception Handling: converts checked exception
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/org/itsallcode/jdbc/ConnectionWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ void executeScript(final String sqlScript) {
if (statements.isEmpty()) {
return;
}
try (StatementBatch batch = this.batch().build()) {
try (StatementBatch batch = this.statementBatch().build()) {
statements.forEach(batch::addBatch);
}
}
Expand All @@ -77,20 +77,20 @@ private SimplePreparedStatement prepareStatement(final String sql) {
new ConvertingPreparedStatement(prepare(sql), paramSetterProvider), sql);
}

StatementBatchBuilder batch() {
StatementBatchBuilder statementBatch() {
return new StatementBatchBuilder(this::createSimpleStatement);
}

private SimpleStatement createSimpleStatement() {
return new SimpleStatement(context, dialect, createStatement());
}

BatchInsertBuilder batchInsert() {
return new BatchInsertBuilder(this::prepareStatement);
PreparedStatementBatchBuilder preparedStatementBatch() {
return new PreparedStatementBatchBuilder(this::prepareStatement);
}

<T> RowBatchInsertBuilder<T> rowBatchInsert() {
return new RowBatchInsertBuilder<>(this::prepareStatement);
<T> RowPreparedStatementBatchBuilder<T> rowPreparedStatementBatch() {
return new RowPreparedStatementBatchBuilder<>(this::prepareStatement);
}

private PreparedStatement prepare(final String sql) {
Expand Down
18 changes: 9 additions & 9 deletions src/main/java/org/itsallcode/jdbc/DbOperations.java
Original file line number Diff line number Diff line change
Expand Up @@ -120,31 +120,31 @@ <T> SimpleResultSet<T> query(final String sql, final PreparedStatementSetter pre
*
* @return batch statement builder
*/
StatementBatchBuilder batch();
StatementBatchBuilder statementBatch();

/**
* Create a batch insert builder for inserting rows by directly setting values
* of a {@link PreparedStatement}.
* Create a prepared statement batch builder for inserting or updating rows by
* directly setting values of a {@link PreparedStatement}.
* <p>
* If you want to insert rows from an {@link Iterator} or a {@link Stream}, use
* {@link #batchInsert(Class)}.
* {@link #preparedStatementBatch(Class)}.
*
* @return batch insert builder
*/
BatchInsertBuilder batchInsert();
PreparedStatementBatchBuilder preparedStatementBatch();

/**
* Create a row-based batch insert builder for inserting rows from an
* {@link Iterator} or a {@link Stream}.
* Create a row-based prepared statement batch builder for inserting or updating
* rows from an {@link Iterator} or a {@link Stream}.
* <p>
* If you want to insert rows by directly setting values of a
* {@link PreparedStatement}, use {@link #batchInsert()}.
* {@link PreparedStatement}, use {@link #preparedStatementBatch()}.
*
* @param rowType row type
* @param <T> row type
* @return row-based batch insert builder
*/
<T> RowBatchInsertBuilder<T> batchInsert(final Class<T> rowType);
<T> RowPreparedStatementBatchBuilder<T> preparedStatementBatch(final Class<T> rowType);

/**
* Get the original wrapped connection.
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/org/itsallcode/jdbc/SimpleConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -100,21 +100,21 @@ public <T> SimpleResultSet<T> query(final String sql, final PreparedStatementSet
}

@Override
public StatementBatchBuilder batch() {
public StatementBatchBuilder statementBatch() {
checkOperationAllowed();
return connection.batch();
return connection.statementBatch();
}

@Override
public BatchInsertBuilder batchInsert() {
public PreparedStatementBatchBuilder preparedStatementBatch() {
checkOperationAllowed();
return connection.batchInsert();
return connection.preparedStatementBatch();
}

@Override
public <T> RowBatchInsertBuilder<T> batchInsert(final Class<T> rowType) {
public <T> RowPreparedStatementBatchBuilder<T> preparedStatementBatch(final Class<T> rowType) {
checkOperationAllowed();
return connection.rowBatchInsert();
return connection.rowPreparedStatementBatch();
}

public Connection getOriginalConnection() {
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/org/itsallcode/jdbc/Transaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -105,21 +105,21 @@ public <T> SimpleResultSet<T> query(final String sql, final PreparedStatementSet
}

@Override
public StatementBatchBuilder batch() {
public StatementBatchBuilder statementBatch() {
checkOperationAllowed();
return connection.batch();
return connection.statementBatch();
}

@Override
public BatchInsertBuilder batchInsert() {
public PreparedStatementBatchBuilder preparedStatementBatch() {
checkOperationAllowed();
return connection.batchInsert();
return connection.preparedStatementBatch();
}

@Override
public <T> RowBatchInsertBuilder<T> batchInsert(final Class<T> rowType) {
public <T> RowPreparedStatementBatchBuilder<T> preparedStatementBatch(final Class<T> rowType) {
checkOperationAllowed();
return connection.rowBatchInsert();
return connection.rowPreparedStatementBatch();
}

public Connection getOriginalConnection() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@

/**
* Direct batch insert using {@link PreparedStatement}. Create a new instance
* using {@link SimpleConnection#batchInsert()}.
* using {@link SimpleConnection#preparedStatementBatch()}.
*/
public class BatchInsert implements AutoCloseable {
public class PreparedStatementBatch implements AutoCloseable {
private final Batch batch;
private final SimplePreparedStatement statement;

BatchInsert(final SimplePreparedStatement statement, final int maxBatchSize) {
PreparedStatementBatch(final SimplePreparedStatement statement, final int maxBatchSize) {
this.statement = Objects.requireNonNull(statement, "statement");
this.batch = new Batch(maxBatchSize, statement, statement::executeBatch);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
import org.itsallcode.jdbc.identifier.Identifier;

/**
* Builder for {@link BatchInsert}. Create a new builder instance using
* {@link SimpleConnection#batchInsert()}.
* Builder for {@link PreparedStatementBatch}. Create a new builder instance
* using {@link SimpleConnection#preparedStatementBatch()}.
*/
public class BatchInsertBuilder {
private static final Logger LOG = Logger.getLogger(BatchInsertBuilder.class.getName());
public class PreparedStatementBatchBuilder {
private static final Logger LOG = Logger.getLogger(PreparedStatementBatchBuilder.class.getName());
/** Default maximum batch size. */
public static final int DEFAULT_MAX_BATCH_SIZE = 200_000;
private final Function<String, SimplePreparedStatement> statementFactory;
Expand All @@ -28,10 +28,22 @@ public class BatchInsertBuilder {
*
* @param statementFactory factory for creating {@link SimplePreparedStatement}.
*/
public BatchInsertBuilder(final Function<String, SimplePreparedStatement> statementFactory) {
public PreparedStatementBatchBuilder(final Function<String, SimplePreparedStatement> statementFactory) {
this.statementFactory = statementFactory;
}

/**
* Define the SQL statement to be used for the batch job, e.g. {@code INSERT} or
* {@code UPDATE}.
*
* @param sql SQL statement
* @return {@code this} for fluent programming
*/
public PreparedStatementBatchBuilder sql(final String sql) {
this.sql = sql;
return this;
}

/**
* Define table and column names used for generating the {@code INSERT}
* statement.
Expand All @@ -41,7 +53,7 @@ public BatchInsertBuilder(final Function<String, SimplePreparedStatement> statem
* @return {@code this} for fluent programming
*/
@SuppressWarnings("java:S3242") // Using List instead of Collection to preserve column order
public BatchInsertBuilder into(final Identifier tableName, final List<Identifier> columnNames) {
public PreparedStatementBatchBuilder into(final Identifier tableName, final List<Identifier> columnNames) {
this.sql = createInsertStatement(tableName, columnNames);
return this;
}
Expand All @@ -55,7 +67,7 @@ public BatchInsertBuilder into(final Identifier tableName, final List<Identifier
* @return {@code this} for fluent programming
*/
@SuppressWarnings("java:S3242") // Using List instead of Collection to preserve column order
public BatchInsertBuilder into(final String tableName, final List<String> columnNames) {
public PreparedStatementBatchBuilder into(final String tableName, final List<String> columnNames) {
return into(Identifier.simple(tableName), columnNames.stream().map(Identifier::simple).toList());
}

Expand All @@ -65,7 +77,7 @@ public BatchInsertBuilder into(final String tableName, final List<String> column
* @param maxBatchSize maximum batch size
* @return {@code this} for fluent programming
*/
public BatchInsertBuilder maxBatchSize(final int maxBatchSize) {
public PreparedStatementBatchBuilder maxBatchSize(final int maxBatchSize) {
this.maxBatchSize = maxBatchSize;
return this;
}
Expand All @@ -81,10 +93,10 @@ private static String createInsertStatement(final Identifier table, final List<I
*
* @return the batch inserter
*/
public BatchInsert build() {
public PreparedStatementBatch build() {
Objects.requireNonNull(this.sql, "sql");
LOG.finest(() -> "Running insert statement '" + sql + "'...");
final SimplePreparedStatement statement = statementFactory.apply(sql);
return new BatchInsert(statement, this.maxBatchSize);
return new PreparedStatementBatch(statement, this.maxBatchSize);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@
import org.itsallcode.jdbc.RowPreparedStatementSetter;
import org.itsallcode.jdbc.SimplePreparedStatement;

class RowBatchInsert<T> implements AutoCloseable {
class RowPreparedStatementBatch<T> implements AutoCloseable {

private final BatchInsert batchInsert;
private final PreparedStatementBatch batchInsert;
private final RowPreparedStatementSetter<T> preparedStatementSetter;

RowBatchInsert(final SimplePreparedStatement statement, final RowPreparedStatementSetter<T> preparedStatementSetter,
RowPreparedStatementBatch(final SimplePreparedStatement statement,
final RowPreparedStatementSetter<T> preparedStatementSetter,
final int maxBatchSize) {
this(new BatchInsert(statement, maxBatchSize), preparedStatementSetter);
this(new PreparedStatementBatch(statement, maxBatchSize), preparedStatementSetter);
}

RowBatchInsert(final BatchInsert batchInsert, final RowPreparedStatementSetter<T> preparedStatementSetter) {
RowPreparedStatementBatch(final PreparedStatementBatch batchInsert,
final RowPreparedStatementSetter<T> preparedStatementSetter) {
this.batchInsert = batchInsert;
this.preparedStatementSetter = preparedStatementSetter;
}
Expand Down
Loading
Loading