Skip to content

Commit 13e59d8

Browse files
yaroslavyaroslav
yaroslav
authored and
yaroslav
committed
introduce batch insert
1 parent 4fa7989 commit 13e59d8

File tree

5 files changed

+76
-6
lines changed

5 files changed

+76
-6
lines changed

src/main/java/com/jcabi/jdbc/JdbcSession.java

+17-2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import java.util.Collection;
3737
import java.util.LinkedList;
3838
import java.util.UUID;
39+
import java.util.concurrent.atomic.AtomicInteger;
3940
import java.util.concurrent.atomic.AtomicReference;
4041
import javax.sql.DataSource;
4142
import lombok.EqualsAndHashCode;
@@ -158,6 +159,8 @@ public final class JdbcSession {
158159
*/
159160
private final transient Collection<Object> args;
160161

162+
private final transient AtomicInteger batchSize;
163+
161164
/**
162165
* Arguments.
163166
*
@@ -196,11 +199,12 @@ public final class JdbcSession {
196199
@SuppressWarnings("PMD.ConstructorOnlyInitializesOrCallOtherConstructors")
197200
public JdbcSession(final DataSource src) {
198201
this.args = new LinkedList<>();
202+
this.batchSize = new AtomicInteger(0);
199203
this.preparations = new LinkedList<>();
200204
this.connection = new AtomicReference<>();
201205
this.auto = true;
202206
this.source = src;
203-
this.preparations.add(new PrepareArgs(this.args));
207+
this.preparations.add(new PrepareArgs(this.args, this.batchSize));
204208
}
205209

206210
/**
@@ -288,7 +292,8 @@ public JdbcSession clear() {
288292
synchronized (this.args) {
289293
this.args.clear();
290294
this.preparations.clear();
291-
this.preparations.add(new PrepareArgs(this.args));
295+
this.batchSize.set(0);
296+
this.preparations.add(new PrepareArgs(this.args, this.batchSize));
292297
}
293298
return this;
294299
}
@@ -368,6 +373,16 @@ public <T> T update(final Outcome<T> outcome)
368373
);
369374
}
370375

376+
public <T> T batchInsert(final Outcome<T> outcome, int batchSize)
377+
throws SQLException {
378+
this.batchSize.set(batchSize);
379+
return this.run(
380+
outcome,
381+
new Connect.WithKeys(this.query),
382+
Request.EXECUTE_BATCH_UPDATE
383+
);
384+
}
385+
371386
/**
372387
* Call an SQL stored procedure.
373388
*

src/main/java/com/jcabi/jdbc/PrepareArgs.java

+16-3
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import java.sql.Types;
3636
import java.util.Collection;
3737
import java.util.Collections;
38+
import java.util.concurrent.atomic.AtomicInteger;
3839

3940
/**
4041
* Prepare arguments.
@@ -48,12 +49,15 @@ final class PrepareArgs implements Preparation {
4849
*/
4950
private final transient Collection<Object> args;
5051

52+
private final AtomicInteger updateBatchSize;
53+
5154
/**
5255
* Ctor.
5356
* @param arguments Arguments
5457
*/
55-
PrepareArgs(final Collection<Object> arguments) {
58+
PrepareArgs(final Collection<Object> arguments, final AtomicInteger updateBatchSize) {
5659
this.args = Collections.unmodifiableCollection(arguments);
60+
this.updateBatchSize = updateBatchSize;
5761
}
5862

5963
@Override
@@ -64,8 +68,14 @@ final class PrepareArgs implements Preparation {
6468
}
6569
)
6670
public void prepare(final PreparedStatement stmt) throws SQLException {
67-
int pos = 1;
71+
int argNumber = 1;
6872
for (final Object arg : this.args) {
73+
int pos;
74+
if (this.updateBatchSize.get() != 0) {
75+
pos = (argNumber - 1) % this.updateBatchSize.get() + 1;
76+
} else {
77+
pos = argNumber;
78+
}
6979
if (arg == null) {
7080
stmt.setNull(pos, Types.NULL);
7181
} else if (arg instanceof Long) {
@@ -85,7 +95,10 @@ public void prepare(final PreparedStatement stmt) throws SQLException {
8595
} else {
8696
stmt.setObject(pos, arg);
8797
}
88-
++pos;
98+
if (this.updateBatchSize.get() != 0 && argNumber % this.updateBatchSize.get() == 0) {
99+
stmt.addBatch();
100+
}
101+
++argNumber;
89102
}
90103
}
91104
}

src/main/java/com/jcabi/jdbc/Request.java

+12
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,18 @@ public ResultSet fetch(final PreparedStatement stmt)
6464
}
6565
};
6666

67+
/**
68+
* Execute update.
69+
*/
70+
Request EXECUTE_BATCH_UPDATE = new Request() {
71+
@Override
72+
public ResultSet fetch(final PreparedStatement stmt)
73+
throws SQLException {
74+
stmt.executeBatch();
75+
return stmt.getGeneratedKeys();
76+
}
77+
};
78+
6779
/**
6880
* Execute query.
6981
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.jcabi.jdbc;
2+
3+
public interface UpdateBatch {
4+
}

src/test/java/com/jcabi/jdbc/JdbcSessionITCase.java src/test/java/com/jcabi/jdbc/JdbcSessionITTest.java

+27-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
* @since 0.1
5252
*/
5353
@Testcontainers(disabledWithoutDocker = true)
54-
final class JdbcSessionITCase {
54+
final class JdbcSessionITTest {
5555

5656
/**
5757
* The database container.
@@ -60,6 +60,32 @@ final class JdbcSessionITCase {
6060
private final JdbcDatabaseContainer<?> container =
6161
new PostgreSQLContainer<>("postgres:9.6.12");
6262

63+
@Test
64+
void batchInsert() throws Exception {
65+
final DataSource source = this.source();
66+
new JdbcSession(source)
67+
.sql("CREATE TABLE IF NOT EXISTS transactions (type VARCHAR(4), amount INTEGER)")
68+
.execute()
69+
.sql("INSERT INTO transactions (type, amount) VALUES (?, ?)")
70+
.set("buy").set(42)
71+
.set("sell").set(5)
72+
.set("sell").set(12)
73+
.set("sell").set(345)
74+
.set("buy").set(1)
75+
.set("sell").set(324)
76+
.set("buy").set(42)
77+
.set("buy").set(8)
78+
.batchInsert(Outcome.NOT_EMPTY, 2);
79+
MatcherAssert.assertThat(
80+
new JdbcSession(source)
81+
.sql("SELECT SUM(amount) FROM transactions")
82+
.select(new SingleOutcome<>(Long.class)),
83+
Matchers.equalTo(
84+
42L + 5 + 12 + 345 + 1 + 324 + 42 + 8
85+
)
86+
);
87+
}
88+
6389
/**
6490
* JdbcSession can do PostgreSQL manipulations.
6591
*

0 commit comments

Comments
 (0)