Database patterns for Java Spring — R2DBC (reactive), JPA/Hibernate (servlet), PostgreSQL, MySQL, connection pooling (HikariCP/r2dbc-pool), Flyway migrations, and query optimization. Use when writing @Entity or R2DBC models, creating Repository interfaces, writing @Query methods, planning Flyway migrations, tuning connection pools, or reviewing SQL performance. Includes scripts/validate-migration.sh for migration file validation.
Installation
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
HIGH 80%+: new @Entity OR new repository OR new query OR schema migration
MEDIUM 40-79%: existing repo modification (e.g., add finder method) OR connection pool config
LOW 1-39%: service that uses repository, no DB code change
ZERO: project has no JPA / R2DBC (verify build.gradle)
Database Patterns
Stack Decision
Criterion
JPA / HikariCP
R2DBC / R2DBC Pool
Runtime
Spring MVC (blocking)
Spring WebFlux (reactive)
Repository
JpaRepository
ReactiveCrudRepository
Transaction
@Transactional
@Transactional + TransactionalOperator
PG driver
org.postgresql:postgresql
org.postgresql:r2dbc-postgresql
MySQL driver
com.mysql.cj.jdbc.Driver
io.asyncer:r2dbc-mysql
Engine Differences
Aspect
PostgreSQL
MySQL
PK strategy
GENERATED ALWAYS AS IDENTITY / SEQUENCE
BIGINT UNSIGNED AUTO_INCREMENT
JPA @GeneratedValue
SEQUENCE + @SequenceGenerator
IDENTITY
Strings
text (no storage diff vs varchar)
VARCHAR(n) + utf8mb4 required
Timestamps
timestamptz (always TZ-aware)
DATETIME(3) (store in UTC)
Covering index
INCLUDE (col)
List all cols in key (no INCLUDE)
Partial index
WHERE clause on index
Not supported (use composite)
Concurrent index
CREATE INDEX CONCURRENTLY
ALGORITHM=INPLACE, LOCK=NONE
Transactional DDL
Yes
No (implicit commit)
Default isolation
READ_COMMITTED
REPEATABLE_READ (gap locks)
Critical Rules (Both Engines)
@SQLRestriction not @Where — Hibernate 6+
FetchType.LAZY always — JOIN FETCH / @EntityGraph at call site
No .block() in reactive — use R2DBC on WebFlux
open-in-view: false — always disable
Parameterized queries only — never concatenate user input
DTO projections for read-only — skip entity lifecycle overhead
Migration Safety (Expand-Contract)
Expand — add nullable column; code writes both old+new
Migrate — backfill in batches (1000 rows), not single UPDATE
Contract — add NOT NULL / drop old column in separate deploy
Always safe: add nullable column, index (CONCURRENTLY/INPLACE), add table.
Never in prod: DROP without expand-contract, ALTER to smaller type, TRUNCATE.
Verification Checklist
No @Data on entities; use @Getter + @NoArgsConstructor(PROTECTED) + builder
@EntityGraph / JOIN FETCH for known N+1 paths
DTO projections for read-only queries
@Transactional(readOnly = true) on query methods
HikariCP leak detection enabled in non-prod
Migrations follow V{n}__{description}.sql naming
Large table changes use online DDL or batch strategy