Skip to content

Conservatively handle JDBC MySQL-family batch inserts#3896

Open
radovanradic wants to merge 15 commits into
5.1.xfrom
mariadb-batch
Open

Conservatively handle JDBC MySQL-family batch inserts#3896
radovanradic wants to merge 15 commits into
5.1.xfrom
mariadb-batch

Conversation

@radovanradic

Copy link
Copy Markdown
Contributor

Related to issue #3893

PR Summary

  • Refines JDBC batch insert support for MySQL-family databases.
  • Allows MariaDB JDBC batch inserts only when generated keys are not required.
  • Keeps MariaDB generated-id saveAll on the fallback path because batched generated-key behavior is driver-option dependent.
  • Allows MySQL JDBC generated-id batches when JDBC metadata reports support for batch updates and generated keys.
  • Makes generated-key handling operation-aware:
    • entity-returning inserts, cascade persist, and post-persist listeners still require generated keys;
    • void and count-returning insert methods can use the no-generated-key batch path.
  • Keeps other dialect behavior unchanged.
  • Adds focused coverage for:
    • MariaDB fallback and no-generated-key batching;
    • MySQL JDBC generated-key batching;
    • H2/Postgres void and count-returning insert behavior;
    • generated-key requirement detection used by batch insert selection.
  • Support-level tests verify batch/fallback decisions directly, and dialect integration tests verify repository-visible behavior and database state.

Notes

  • MariaDB saveAll for entities with generated IDs intentionally uses the per-row fallback path so generated IDs are populated reliably.
  • Older MariaDB drivers should remain guarded by JDBC metadata: if batch updates are not reported as supported, the MariaDB batch path is not enabled.

Copilot AI review requested due to automatic review settings June 3, 2026 08:33
@radovanradic radovanradic added the type: improvement A minor improvement to an existing feature label Jun 3, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refines how Micronaut Data JDBC selects the batch-insert path for MySQL-family databases, keeping MariaDB conservative around generated keys while allowing MySQL Connector/J batching when JDBC metadata indicates it’s safe. It also makes generated-key retrieval conditional on whether the calling operation actually requires keys (entity-returning / cascade / listeners) versus void/count insert methods.

Changes:

  • Introduces SqlBatchSupport (internal) to centralize batch-insert support checks, including JDBC metadata-based MySQL/MariaDB discrimination and operation-aware generated-key requirements.
  • Updates JDBC insert batching to optionally use Statement.NO_GENERATED_KEYS for void/count inserts (avoiding unnecessary key retrieval and entity mutation).
  • Adds targeted unit/integration tests covering MySQL vs MariaDB behavior and void/count insert semantics across multiple dialects.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
data-runtime/src/main/java/io/micronaut/data/runtime/operations/internal/sql/SqlBatchSupport.java New internal helper encapsulating dialect/JDBC metadata batch-insert capability checks and generated-key requirement detection.
data-runtime/src/main/java/io/micronaut/data/runtime/operations/internal/sql/AbstractSqlRepositoryOperations.java Delegates batch-insert support checks to SqlBatchSupport.
data-jdbc/src/main/java/io/micronaut/data/jdbc/operations/DefaultJdbcRepositoryOperations.java Uses operation-aware generated-key requirements and JDBC metadata to choose batch vs fallback and whether to request generated keys.
data-runtime/src/test/groovy/io/micronaut/data/runtime/operations/internal/sql/SqlBatchSupportSpec.groovy Unit tests for SqlBatchSupport decision matrix and generated-key requirement detection.
data-jdbc/src/test/groovy/io/micronaut/data/jdbc/mysql/MySqlBatchInsertSpec.groovy MySQL integration coverage for generated-id batching and non-mutating void insertAll.
data-jdbc/src/test/java/io/micronaut/data/jdbc/mysql/MySqlBatchRecord.java Test entity (record) for MySQL batch insert scenarios.
data-jdbc/src/test/groovy/io/micronaut/data/jdbc/mariadb/MariaBatchInsertSpec.groovy MariaDB integration coverage for fallback vs no-generated-key batching behavior.
data-jdbc/src/test/java/io/micronaut/data/jdbc/mariadb/MariaBatchRecord.java Test entity (record) for MariaDB batch insert scenarios.
data-jdbc/src/test/groovy/io/micronaut/data/jdbc/postgres/PostgresBatchInsertSpec.groovy Ensures void/count inserts don’t mutate input ids (no generated-key requirement) on Postgres.
data-jdbc/src/test/groovy/io/micronaut/data/jdbc/h2/H2BatchInsertSpec.groovy Ensures void/count inserts don’t mutate input ids (no generated-key requirement) on H2.

Copilot AI review requested due to automatic review settings June 3, 2026 13:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

data-jdbc/src/main/java/io/micronaut/data/jdbc/operations/DefaultJdbcRepositoryOperations.java:862

  • requiresGeneratedKeys is computed for the batch decision, but the per-row fallback path still builds JdbcEntityOperations without any way to disable generated-key retrieval. For void/count insert methods (where requiresGeneratedKeys is false), falling back (e.g. when JDBC metadata says batch updates aren’t supported) will still request generated keys and can mutate input entity IDs, which undermines the operation-aware generated-key handling introduced here.
            if (!isSupportsBatchInsert(ctx, persistentEntity, storedQuery, requiresGeneratedKeys)) {
                return operation.split().stream()
                    .map(persistOp -> {
                        JdbcEntityOperations<T> op = new JdbcEntityOperations<>(ctx, storedQuery, persistentEntity, persistOp.getEntity(), true);
                        op.persist();

Copilot AI review requested due to automatic review settings June 3, 2026 13:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

@sonarqubecloud

sonarqubecloud Bot commented Jun 3, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: improvement A minor improvement to an existing feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants