Files

3.7 KiB

soft-delete

Companion module for the ankurm.com article Soft Delete in Hibernate 7: @SoftDelete vs @SQLDelete + @SQLRestriction. Every claim in the article comes from a test here; each test writes what it observed to output/. Tests that touch a database run twice, against in-memory H2 and against a real PostgreSQL 17 container started by Testcontainers.

Versions

Component Version Notes
Hibernate ORM 7.4.14.Final newest 7.x GA on Maven Central on 2026-10-28 (8.0.0.Beta4 is also listed; it is not GA). Overrides the 7.4.5.Final that Spring Boot 4.1.1 manages
Spring Boot / Spring Data JPA 4.1.1 / 4.1.1 parent POM; only the Spring Data test needs it
H2 2.4.240 in memory
PostgreSQL 17.11 postgres:17-alpine through Testcontainers 2.0.5 (needs a running Docker daemon)
Java 25 (Temurin 25.0.5+8)

SoftDeleteType in the shipped jar: ACTIVE, DELETED, TIMESTAMP (see output/00-javap.txt). TIMESTAMP is absent from 6.6.0.Final and present in 7.0.0.Final (both jars inspected with javap).

Run

./scripts/run-all.sh      # javap dump + mvn clean test; regenerates everything in output/

Mapping styles

Class Mapping
ArticleDeleted @SoftDelete (default, boolean deleted)
ArticleActive @SoftDelete(strategy = ACTIVE)
ArticleStamped @SoftDelete(strategy = TIMESTAMP, columnName = "deleted_at")
ArticleManual @SQLDelete + @SQLRestriction
ArticleYesNo converter = YesNoConverter.class
SoftBase / Note @SoftDelete on a @MappedSuperclass
Author, Book, Tag, Reader, Shelf, Item associations, collection-level @SoftDelete, cascades
ArticleRepository Spring Data JPA

Output

File What it shows
00-javap.txt javap of SoftDelete, SoftDeleteType, SQLDelete, SQLRestriction from the shipped jar
01-api-shape.txt enum values, default column names and annotation defaults read by reflection
02-ddl-and-sql.txt DDL and the SQL for persist / find / remove / count under all four styles; deleting an already-deleted row
03-restore-and-native.txt native queries bypass the predicate, HQL cannot restore, stale persistence context, restore per strategy
04-unique-constraints.txt six unique-index variants on H2 and PostgreSQL: plain, (email, deleted), partial, (email, deleted_at), NULLS NOT DISTINCT
05-associations.txt deleted parent, new child of a deleted parent, collections, many-to-many (join rows are soft-deleted too), collection-level @SoftDelete, cascades, purging
06-lazy-to-one.txt @ManyToOne(fetch = LAZY) towards a @SoftDelete entity is rejected at startup
07-bulk-and-sqldelete.txt HQL bulk delete (soft vs real DELETE), stale double delete, converter, @MappedSuperclass
08-spring-data.txt deleteById, findById, count, derived deletes, save of a soft-deleted instance, bulk and native @Query, deleteAll

Not covered (not run)

@SoftDelete with inheritance hierarchies, second-level cache, Envers, SQL Server / Oracle / MySQL (filtered or function-based indexes there are described in the article but were not executed), and Spring Data on PostgreSQL (the Spring test runs on H2).