New posts for Spring and Hibernate

This commit is contained in:
2026-11-06 01:05:17 +05:30
parent b83cc9988e
commit 0245c00033
57 changed files with 2113 additions and 0 deletions
+76
View File
@@ -0,0 +1,76 @@
# javap of the shipped hibernate-core-7.4.14.Final.jar
$ javap -cp hibernate-core-7.4.14.Final.jar org.hibernate.annotations.UuidGenerator
Compiled from "UuidGenerator.java"
public interface org.hibernate.annotations.UuidGenerator extends java.lang.annotation.Annotation {
public abstract org.hibernate.annotations.UuidGenerator$Style style();
public abstract java.lang.Class<? extends org.hibernate.id.uuid.UuidValueGenerator> algorithm();
}
$ javap -cp hibernate-core-7.4.14.Final.jar org.hibernate.annotations.UuidGenerator$Style
Compiled from "UuidGenerator.java"
public final class org.hibernate.annotations.UuidGenerator$Style extends java.lang.Enum<org.hibernate.annotations.UuidGenerator$Style> {
public static final org.hibernate.annotations.UuidGenerator$Style AUTO;
public static final org.hibernate.annotations.UuidGenerator$Style RANDOM;
public static final org.hibernate.annotations.UuidGenerator$Style TIME;
public static final org.hibernate.annotations.UuidGenerator$Style VERSION_6;
public static final org.hibernate.annotations.UuidGenerator$Style VERSION_7;
public static org.hibernate.annotations.UuidGenerator$Style[] values();
public static org.hibernate.annotations.UuidGenerator$Style valueOf(java.lang.String);
static {};
}
$ javap -cp hibernate-core-7.4.14.Final.jar org.hibernate.id.uuid.UuidValueGenerator
Compiled from "UuidValueGenerator.java"
public interface org.hibernate.id.uuid.UuidValueGenerator {
public abstract java.util.UUID generateUuid(org.hibernate.engine.spi.SharedSessionContractImplementor);
}
$ javap -cp hibernate-core-7.4.14.Final.jar org.hibernate.id.uuid.UuidVersion7Strategy
Compiled from "UuidVersion7Strategy.java"
public class org.hibernate.id.uuid.UuidVersion7Strategy implements org.hibernate.id.UUIDGenerationStrategy,org.hibernate.id.uuid.UuidValueGenerator {
public static final org.hibernate.id.uuid.UuidVersion7Strategy INSTANCE;
public org.hibernate.id.uuid.UuidVersion7Strategy();
public org.hibernate.id.uuid.UuidVersion7Strategy(java.time.Instant, long);
public int getGeneratedVersion();
public java.util.UUID generateUUID(org.hibernate.engine.spi.SharedSessionContractImplementor);
public java.util.UUID generateUuid(org.hibernate.engine.spi.SharedSessionContractImplementor);
static {};
}
$ javap -cp hibernate-core-7.4.14.Final.jar org.hibernate.id.SequenceMismatchStrategy
Compiled from "SequenceMismatchStrategy.java"
public final class org.hibernate.id.SequenceMismatchStrategy extends java.lang.Enum<org.hibernate.id.SequenceMismatchStrategy> {
public static final org.hibernate.id.SequenceMismatchStrategy LOG;
public static final org.hibernate.id.SequenceMismatchStrategy EXCEPTION;
public static final org.hibernate.id.SequenceMismatchStrategy FIX;
public static final org.hibernate.id.SequenceMismatchStrategy NONE;
public static org.hibernate.id.SequenceMismatchStrategy[] values();
public static org.hibernate.id.SequenceMismatchStrategy valueOf(java.lang.String);
public static org.hibernate.id.SequenceMismatchStrategy interpret(java.lang.Object);
static {};
}
$ javap -cp hibernate-core-7.4.14.Final.jar org.hibernate.id.enhanced.StandardOptimizerDescriptor
Compiled from "StandardOptimizerDescriptor.java"
public final class org.hibernate.id.enhanced.StandardOptimizerDescriptor extends java.lang.Enum<org.hibernate.id.enhanced.StandardOptimizerDescriptor> implements org.hibernate.id.enhanced.OptimizerDescriptor {
public static final org.hibernate.id.enhanced.StandardOptimizerDescriptor NONE;
public static final org.hibernate.id.enhanced.StandardOptimizerDescriptor HILO;
public static final org.hibernate.id.enhanced.StandardOptimizerDescriptor LEGACY_HILO;
public static final org.hibernate.id.enhanced.StandardOptimizerDescriptor POOLED;
public static final org.hibernate.id.enhanced.StandardOptimizerDescriptor POOLED_LO;
public static final org.hibernate.id.enhanced.StandardOptimizerDescriptor POOLED_LOTL;
public static org.hibernate.id.enhanced.StandardOptimizerDescriptor[] values();
public static org.hibernate.id.enhanced.StandardOptimizerDescriptor valueOf(java.lang.String);
public java.lang.String getExternalName();
public java.lang.Class<? extends org.hibernate.id.enhanced.Optimizer> getOptimizerClass();
public boolean isPooled();
public static org.hibernate.id.enhanced.OptimizerDescriptor fromExternalName(java.lang.String);
static {};
}
$ javap java.util.UUID (static members only)
public static java.util.UUID randomUUID();
public static java.util.UUID nameUUIDFromBytes(byte[]);
public static java.util.UUID fromString(java.lang.String);
static {};
@@ -0,0 +1,7 @@
# UuidGenerator.Style constants per hibernate-core release (javap of each jar; produced by hand while writing the article, not by scripts/run-all.sh)
hibernate-core-6.5.2.Final: AUTO RANDOM TIME | UuidVersion7Strategy in jar: 0
hibernate-core-6.6.8.Final: AUTO RANDOM TIME | UuidVersion7Strategy in jar: 0
hibernate-core-7.0.0.Final: AUTO RANDOM TIME VERSION_6 VERSION_7 | UuidVersion7Strategy in jar: 1
hibernate-core-7.4.0.Final: AUTO RANDOM TIME VERSION_6 VERSION_7 | UuidVersion7Strategy in jar: 1
hibernate-core-7.4.14.Final: AUTO RANDOM TIME VERSION_6 VERSION_7 | UuidVersion7Strategy in jar: 1
+57
View File
@@ -0,0 +1,57 @@
UuidGenerator.Style values and what the generated UUIDs look like. Hibernate 7.4.14.Final, JDK 25.0.3+9-LTS-195
== The enum and the annotation, from the shipped jar
Style values : [AUTO, RANDOM, TIME, VERSION_6, VERSION_7]
annotation attributes : [algorithm, style]
== Does the JDK itself generate version 7? (public static methods of java.util.UUID)
static factories: [fromString, nameUUIDFromBytes, randomUUID]
== GenerationType.UUID (JPA) (UuidV4Item, 2000 persists in one transaction)
first three : [5b257f75-63bc-4f48-905d-65bac3459d13, 8b636cac-72ba-4740-baa4-960522598e0f, 7563a4d5-dfe5-4be5-b1f5-55e71a83eaec]
version nibble of every id : [4], variant : [2]
string/byte order vs generation order : 1017 of 1999 neighbours are out of order
== bare @GeneratedValue on a UUID (AUTO) (AutoUuidItem, 2000 persists in one transaction)
first three : [35ad5be5-7f04-4dc8-83b9-f2266e101ab0, 78a0cefb-b172-46e4-94aa-60212ad0b190, 162be54a-33b8-4018-8df9-5e43836cc2af]
version nibble of every id : [4], variant : [2]
string/byte order vs generation order : 1005 of 1999 neighbours are out of order
== Style.TIME (UuidTimeItem, 2000 persists in one transaction)
first three : [c0a802bb-a1ad-1754-81a1-ad076a3225a0, c0a802bb-a1ad-1754-81a1-ad076a3225a1, c0a802bb-a1ad-1754-81a1-ad076a3225a2]
version nibble of every id : [1], variant : [2]
string/byte order vs generation order : 0 of 1999 neighbours are out of order
UUID.timestamp() of first / last id (100ns ticks since 1582) : 528224823942841019 / 528224823942841019
most significant 32 bits (time_low) of first three : [c0a802bb, c0a802bb, c0a802bb]
== Style.VERSION_6 (UuidV6Item, 2000 persists in one transaction)
first three : [1f1d9490-534d-6627-8be9-341e19966c04, 1f1d9490-534d-6627-8bea-9c10655ddb7b, 1f1d9490-534d-6627-8beb-b5f923905e48]
version nibble of every id : [6], variant : [2]
string/byte order vs generation order : 0 of 1999 neighbours are out of order
== Style.VERSION_7 (UuidV7Item, 2000 persists in one transaction)
first three : [01a1ad07-6af9-7f60-91e5-a074a2e61b15, 01a1ad07-6af9-7f60-bafb-92ecaabdd57e, 01a1ad07-6af9-7f61-84be-68a7813aa2e1]
version nibble of every id : [7], variant : [2]
string/byte order vs generation order : 0 of 1999 neighbours are out of order
first 48 bits as Unix milliseconds : 1793904306937 -> 2026-11-05T18:45:06.937Z
== uuid-creator getTimeOrderedEpoch() (UuidCreatorV7Item, 2000 persists in one transaction)
first three : [01a1ad07-6b4a-7727-8708-c7b485cd7cc5, 01a1ad07-6b4a-7727-8709-75a505ff49d2, 01a1ad07-6b4a-7727-870a-1991eca1f5b5]
version nibble of every id : [7], variant : [2]
string/byte order vs generation order : 0 of 1999 neighbours are out of order
first 48 bits as Unix milliseconds : 1793904307018 -> 2026-11-05T18:45:07.018Z
== hand-written UuidV7Generator (HandRolledV7Item, 2000 persists in one transaction)
first three : [01a1ad07-6ba5-7041-a4e3-8df974d6a001, 01a1ad07-6ba5-7042-8be9-c72dadba0e18, 01a1ad07-6ba5-7043-87de-73e7de8dbb54]
version nibble of every id : [7], variant : [2]
string/byte order vs generation order : 0 of 1999 neighbours are out of order
first 48 bits as Unix milliseconds : 1793904307109 -> 2026-11-05T18:45:07.109Z
== Style.TIME is not a clock-ordered v1: what changes between ids created 30 ms apart
c0a802bb-a1ad-1754-81a1-ad076be82d70 msb=c0a802bba1ad1754 lsb=81a1ad076be82d70
c0a802bb-a1ad-1754-81a1-ad076c092d71 msb=c0a802bba1ad1754 lsb=81a1ad076c092d71
c0a802bb-a1ad-1754-81a1-ad076c282d72 msb=c0a802bba1ad1754 lsb=81a1ad076c282d72
c0a802bb-a1ad-1754-81a1-ad076c482d73 msb=c0a802bba1ad1754 lsb=81a1ad076c482d73
distinct most-significant halves among them : 1 (IPv4 address of this host + a per-JVM value, fixed for the life of the JVM)
first 32 bits equal this host's IPv4 address : true
UUID.timestamp() (what a real version 1 would use as its clock) is the same for all four : 1 distinct value(s)
@@ -0,0 +1,7 @@
Cost of generating one UUID in memory (single thread, 2,000,000 ids after 500,000 warm-up; indicative, machine dependent)
UUID.randomUUID() 351 ns per id
Hibernate VERSION_7 769 ns per id
Hibernate VERSION_6 680 ns per id
Hibernate TIME (v1) 22 ns per id
uuid-creator v7 352 ns per id
UuidV7Generator (hand-written) 709 ns per id
@@ -0,0 +1,43 @@
IDENTITY vs SEQUENCE vs TABLE: generated DDL, SQL, and when the INSERT runs
######## H2 ########
database: H2Dialect / H2 2.4.240 (2025-09-22)
== DDL Hibernate generates
create sequence seq_one_item start with 1 increment by 1;
create sequence seq_pooled_item start with 1 increment by 50;
create sequence SeqDefaultItem_SEQ start with 1 increment by 50;
create table hibernate_sequences (next_val bigint, sequence_name varchar(255) not null, primary key (sequence_name));
insert into hibernate_sequences(sequence_name, next_val) values ('default',0);
create table IdentityItem (id bigint generated by default as identity, name varchar(255), primary key (id));
create table SeqDefaultItem (id bigint not null, name varchar(255), primary key (id));
create table SeqOneItem (id bigint not null, name varchar(255), primary key (id));
create table SeqPooledItem (id bigint not null, name varchar(255), primary key (id));
create table TableItem (id bigint not null, name varchar(255), primary key (id));
== IDENTITY: persist() runs the INSERT immediately
-- persist(item) -- no flush(), no commit() yet
sql> insert into IdentityItem (name,id) values (?,default)
item.getId() right after persist : 1
rows visible after rollback : 0
== SEQUENCE, allocationSize = 1: one sequence call per entity
persist 120 entities, one transaction
sequence calls : 120 inserts : 120
first ids : [1, 2, 3, 4, 5] ... last id : 120
== SEQUENCE, allocationSize = 50 (pooled optimizer): one sequence call per 50 entities
persist 120 entities, one transaction
sequence calls : 4 inserts : 120
first ids : [1, 2, 3, 4, 5] ... last id : 120
sequence statements : [select next value for seq_pooled_item]
(the first allocation of a fresh sequence costs two calls: one to learn the starting value, one to learn the upper bound of the first block of 50)
persist another 120 entities, same SessionFactory : sequence calls : 2
== TABLE generator: one read + one update of the generator row per allocation
persist 120 entities: statements other than the 120 INSERTs : 8 (seen by the JDBC counter; Hibernate's StatementInspector does not see them)
sql> select next_val from hibernate_sequences where sequence_name=? for update
sql> update hibernate_sequences set next_val=? where next_val=? and sequence_name=?
######## POSTGRES ########
SKIPPED: no Docker daemon was reachable when this transcript was generated, so PostgreSQL was not run.
@@ -0,0 +1,17 @@
Sequence names Hibernate 7 picks when you name nothing, and the legacy switch
######## H2 ########
database: H2Dialect / H2 2.4.240 (2025-09-22)
== hibernate.id.db_structure_naming_strategy = standard (entities: AutoLongItem, SeqDefaultItem)
create sequence AutoLongItem_SEQ start with 1 increment by 50;
create sequence SeqDefaultItem_SEQ start with 1 increment by 50;
== hibernate.id.db_structure_naming_strategy = legacy (entities: AutoLongItem, SeqDefaultItem)
create sequence hibernate_sequence start with 1 increment by 1;
== hibernate.id.db_structure_naming_strategy = single (entities: AutoLongItem, SeqDefaultItem)
create sequence hibernate_sequence start with 1 increment by 1;
######## POSTGRES ########
SKIPPED: no Docker daemon was reachable when this transcript was generated, so PostgreSQL was not run.
+19
View File
@@ -0,0 +1,19 @@
10,000 inserts: IDENTITY vs SEQUENCE vs UUID, hibernate.jdbc.batch_size=50, flush+clear every 50 rows
######## H2 ########
database: H2Dialect / H2 2.4.240 (2025-09-22)
timings are wall-clock milliseconds on one developer machine, one run each after a warm-up pass: indicative, not a benchmark
IDENTITY 331 ms prepared=10000 (insert=10000, sequence=0) addBatch=0 executeBatch=0 executeSingle=10000
SEQUENCE allocationSize=1 226 ms prepared=10200 (insert=200, sequence=10000) addBatch=10000 executeBatch=200 executeSingle=10000
SEQUENCE allocationSize=50 46 ms prepared=400 (insert=200, sequence=200) addBatch=10000 executeBatch=200 executeSingle=200
UUID v4 (GenerationType.UUID) 98 ms prepared=200 (insert=200, sequence=0) addBatch=10000 executeBatch=200 executeSingle=0
UUID v7 (Style.VERSION_7) 64 ms prepared=200 (insert=200, sequence=0) addBatch=10000 executeBatch=200 executeSingle=0
Hibernate Statistics for the whole session factory (all rows above, including the warm-up): entityInsertCount=55000 prepareStatementCount=23101
Same SEQUENCE allocationSize=50 entity, hibernate.jdbc.batch_size NOT set:
SEQUENCE allocationSize=50 68 ms prepared=10201 (insert=10000, sequence=201) addBatch=0 executeBatch=0 executeSingle=10201
######## POSTGRES ########
SKIPPED: no Docker daemon was reachable when this transcript was generated, so PostgreSQL was not run.
@@ -0,0 +1,9 @@
hibernate.order_inserts on a parent/child graph (1,000 parents x 3 children, batch_size=50, flush+clear every 50 parents)
######## H2 ########
database: H2Dialect / H2 2.4.240 (2025-09-22)
order_inserts=false 266 ms prepared=2082 (insert=2000, sequence=82) addBatch=4000 executeBatch=2000 executeSingle=82
order_inserts=true 118 ms prepared=122 (insert=40, sequence=82) addBatch=4000 executeBatch=80 executeSingle=82
######## POSTGRES ########
SKIPPED: no Docker daemon was reachable when this transcript was generated, so PostgreSQL was not run.
@@ -0,0 +1,30 @@
Mapping says allocationSize=50, the database sequence says INCREMENT BY 1 (schema created by hand)
######## H2 ########
== hibernate.id.sequence.increment_size_mismatch_strategy = (unset)
SessionFactory startup FAILED: MappingException -> MappingException: The increment size of the [seq_pooled_item] sequence is set to [50] in the entity mapping but the mapped database sequence increment size is [1]
== hibernate.id.sequence.increment_size_mismatch_strategy = EXCEPTION
SessionFactory startup FAILED: MappingException -> MappingException: The increment size of the [seq_pooled_item] sequence is set to [50] in the entity mapping but the mapped database sequence increment size is [1]
== hibernate.id.sequence.increment_size_mismatch_strategy = LOG
SessionFactory started
application instance A : ids [1, -47, -46]
application instance B : FAILED after ids [-46, -45, -44] : ConstraintViolationException -> JdbcSQLIntegrityConstraintViolationException: SQLState 23505, Unique index or primary key violation: "PUBLIC.CONSTRAINT_D PRIMARY KEY ON PUBLIC.SEQPOOLEDITEM(ID) ( /* key:-46 */ CAST(-46 AS BIGINT), 'a2')"; SQL statement:
database sequence INCREMENT BY, as the database sees it : 1
== hibernate.id.sequence.increment_size_mismatch_strategy = FIX
SessionFactory started
application instance A : ids [1, 2, 3]
application instance B : ids [4, 5, 6]
database sequence INCREMENT BY, as the database sees it : 1
== hibernate.id.sequence.increment_size_mismatch_strategy = NONE
SessionFactory started
application instance A : ids [1, -47, -46]
application instance B : FAILED after ids [-46, -45, -44] : ConstraintViolationException -> JdbcSQLIntegrityConstraintViolationException: SQLState 23505, Unique index or primary key violation: "PUBLIC.CONSTRAINT_D PRIMARY KEY ON PUBLIC.SEQPOOLEDITEM(ID) ( /* key:-46 */ CAST(-46 AS BIGINT), 'a2')"; SQL statement:
database sequence INCREMENT BY, as the database sees it : 1
######## POSTGRES ########
SKIPPED: no Docker daemon was reachable when this transcript was generated, so PostgreSQL was not run.
@@ -0,0 +1,12 @@
Mapping says allocationSize=1, the database sequence says INCREMENT BY 50
######## H2 ########
== hibernate.id.sequence.increment_size_mismatch_strategy = (unset)
ids : [1, 51, 101, 151]
== hibernate.id.sequence.increment_size_mismatch_strategy = FIX
ids : [1, 51, 101, 151]
######## POSTGRES ########
SKIPPED: no Docker daemon was reachable when this transcript was generated, so PostgreSQL was not run.
@@ -0,0 +1,49 @@
What @GeneratedValue (AUTO) and UUID ids become per dialect. DDL only: no database connection is opened for the dialects other than H2. Hibernate 7.4.14.Final
== H2 (org.hibernate.dialect.H2Dialect)
create sequence AutoLongItem_SEQ start with 1 increment by 50;
create table AutoLongItem (id bigint not null, name varchar(255), primary key (id));
create table AutoUuidItem (id uuid not null, name varchar(255), primary key (id));
create table IdentityItem (id bigint generated by default as identity, name varchar(255), primary key (id));
create table UuidCharItem (id char(36) not null, name varchar(255), primary key (id));
create table UuidV7Item (id uuid not null, name varchar(255), primary key (id));
== PostgreSQL (org.hibernate.dialect.PostgreSQLDialect)
create sequence AutoLongItem_SEQ start with 1 increment by 50;
create table AutoLongItem (id bigint not null, name varchar(255), primary key (id));
create table AutoUuidItem (id uuid not null, name varchar(255), primary key (id));
create table IdentityItem (id bigint generated by default as identity, name varchar(255), primary key (id));
create table UuidCharItem (id char(36) not null, name varchar(255), primary key (id));
create table UuidV7Item (id uuid not null, name varchar(255), primary key (id));
== MySQL (org.hibernate.dialect.MySQLDialect)
create table AutoLongItem (id bigint not null, name varchar(255), primary key (id)) engine=InnoDB;
create table AutoLongItem_SEQ (next_val bigint) engine=InnoDB;
create table AutoUuidItem (id binary(16) not null, name varchar(255), primary key (id)) engine=InnoDB;
create table IdentityItem (id bigint not null auto_increment, name varchar(255), primary key (id)) engine=InnoDB;
create table UuidCharItem (id varchar(36) not null, name varchar(255), primary key (id)) engine=InnoDB;
create table UuidV7Item (id binary(16) not null, name varchar(255), primary key (id)) engine=InnoDB;
== MariaDB (org.hibernate.dialect.MariaDBDialect)
create sequence AutoLongItem_SEQ start with 1 increment by 50 nocache;
create table AutoLongItem (id bigint not null, name varchar(255), primary key (id)) engine=InnoDB;
create table AutoUuidItem (id binary(16) not null, name varchar(255), primary key (id)) engine=InnoDB;
create table IdentityItem (id bigint not null auto_increment, name varchar(255), primary key (id)) engine=InnoDB;
create table UuidCharItem (id varchar(36) not null, name varchar(255), primary key (id)) engine=InnoDB;
create table UuidV7Item (id binary(16) not null, name varchar(255), primary key (id)) engine=InnoDB;
== Oracle (org.hibernate.dialect.OracleDialect)
create sequence AutoLongItem_SEQ start with 1 increment by 50;
create table AutoLongItem (id number(19,0) not null, name varchar2(255 char), primary key (id));
create table AutoUuidItem (id raw(16) not null, name varchar2(255 char), primary key (id));
create table IdentityItem (id number(19,0) generated by default as identity, name varchar2(255 char), primary key (id));
create table UuidCharItem (id char(36) not null, name varchar2(255 char), primary key (id));
create table UuidV7Item (id raw(16) not null, name varchar2(255 char), primary key (id));
== SQL Server (org.hibernate.dialect.SQLServerDialect)
create sequence AutoLongItem_SEQ start with 1 increment by 50;
create table AutoLongItem (id bigint not null, name varchar(255), primary key (id));
create table AutoUuidItem (id uniqueidentifier not null, name varchar(255), primary key (id));
create table IdentityItem (id bigint identity not null, name varchar(255), primary key (id));
create table UuidCharItem (id char(36) not null, name varchar(255), primary key (id));
create table UuidV7Item (id uniqueidentifier not null, name varchar(255), primary key (id));
@@ -0,0 +1,8 @@
Primary-key choice vs database file size, H2 file database (MVStore B-tree), file size after the database is closed, 200000 rows per variant, batch_size=50, flush+clear every 50 rows
H2 specific: this is H2's storage engine, not PostgreSQL's or InnoDB's. Timings are indicative (one run, one machine).
variant load ms file KiB
bigint sequence (allocationSize 50) 1244 4944
UUID v4 random 2280 101428
UUID v7 time-ordered 1314 12960
UUID v7 as CHAR(36) 1528 52948
@@ -0,0 +1,2 @@
Primary-key choice vs index size and leaf density, PostgreSQL postgres:17-alpine, 200000 rows per variant, batch_size=50
SKIPPED: no Docker daemon was reachable when this transcript was generated, so PostgreSQL was not run.
@@ -0,0 +1,20 @@
Spring Data JPA save() with application-assigned vs generated ids. Spring Boot parent 4.1.1, Hibernate 7.4.14.Final, H2
== AssignedBook: UUID.randomUUID() assigned in the constructor, no @Version
sql> select ab1_0.id,ab1_0.title from assigned_book ab1_0 where ab1_0.id=?
sql> insert into assigned_book (title,id) values (?,?)
== VersionedBook: same, plus a boxed @Version column
sql> insert into versioned_book (title,version,id) values (?,?,?)
== PersistableBook: same, entity implements Persistable.isNew()
sql> insert into persistable_book (title,id) values (?,?)
== GeneratedBook: @UuidGenerator(style = VERSION_7), id is null until persist
sql> insert into generated_book (title,id) values (?,?)
== saveAll of 100 new AssignedBook rows: selects issued
select statements : 100, insert statements : 100
== saveAll of 100 new GeneratedBook rows: selects issued
select statements : 0, insert statements : 100