SQL Server · CrudLabDB

Batch insert

Feature 14: save many rows at once, in one transaction. If one row fails, nothing is saved (rollback).

JdbcTemplate.batchUpdate vs JPA saveAll()
1 · Rows to insert
The header line is optional. Quote fields that contain commas: "java, sql". An empty code gets the next ART-xxxx. Up to 5000 rows.
Rows get codes like BULK-1030-0001. Try 1000 with each method and compare the time.
2 · How to save them
JavaBatchInsertService
jdbc.batchUpdate(INSERT_SQL, rows, 500, (ps, r) -> {
    ps.setString(1, r.code());
    ps.setString(2, r.title());
    ...
});

// or, with JPA:
repo.saveAll(entities);
repo.flush();
  • The method is @Transactional: a duplicate code throws, and every row of the batch is rolled back.
  • SQL Server allows at most 2100 parameters per statement, so the "already exists?" check runs WHERE code IN (…) in chunks of 1000.
  • Try to insert the sample CSV twice: the second time fails, unless you tick "Skip rows…".
SQL behind this page

Captured by a Hibernate StatementInspector and by the JdbcTemplate code. ? marks a parameter: values are sent separately, which keeps SQL injection out.

Loading this page
1
SELECT
  COUNT(*)                                                                AS total,
  SUM(CASE WHEN deleted = 0 AND archived = 0 THEN 1 ELSE 0 END)           AS active,
  SUM(CASE WHEN deleted = 0 AND archived = 0 AND status = 'DRAFT' THEN 1 ELSE 0 END)       AS drafts,
  SUM(CASE WHEN deleted = 0 AND archived = 0 AND status = 'PUBLISHED' THEN 1 ELSE 0 END)   AS published,
  SUM(CASE WHEN deleted = 0 AND archived = 0 AND status = 'UNPUBLISHED' THEN 1 ELSE 0 END) AS unpublished,
  SUM(CASE WHEN deleted = 0 AND archived = 0 AND pinned = 1 THEN 1 ELSE 0 END)    AS pinned,
  SUM(CASE WHEN deleted = 0 AND favourite = 1 THEN 1 ELSE 0 END)                  AS favourites,
  SUM(CASE WHEN deleted = 0 AND archived = 0 AND is_read = 0 THEN 1 ELSE 0 END)   AS unread,
  SUM(CASE WHEN deleted = 0 AND locked = 1 THEN 1 ELSE 0 END)                     AS locked,
  SUM(CASE WHEN deleted = 0 AND archived = 1 THEN 1 ELSE 0 END)                   AS archived,
  SUM(CASE WHEN deleted = 1 THEN 1 ELSE 0 END)                                    AS trash
FROM article