10 AI Prompts for Hibernate and JPA

Hibernate is powerful and largely invisible when it works — and deeply confusing when it does not. N+1 queries, LazyInitializationException, detached entity exceptions, first-level cache surprises, and migration scripts that silently break the schema are problems that most Java developers encounter repeatedly throughout their careers. I started keeping a list of Hibernate bugs that slipped through review in a large Spring Boot 3 codebase — things that passed all unit tests, passed all integration tests, and only surfaced under production load or after a schema migration. After a dozen entries the pattern was clear: almost all of them were diagnosable by AI if you pasted the right context. The problem was knowing which context to paste. These 10 prompts encode that knowledge — each one specifies exactly what diagnostic data to provide, so the AI can reason about the real problem rather than the surface symptom. AI assistants handle Hibernate well: they know the JPA specification, the Hibernate-specific extensions, the Spring Data abstractions, and the performance implications of every mapping decision.

This post gives you 10 copy-paste AI prompts for Hibernate and JPA development. Each prompt is designed to produce production-quality output — not tutorial-level simplifications — and includes enough context for the AI to reason about the trade-offs specific to your use case.

For foundational reading, see the Hibernate Tutorials series. For complementary AI prompts, see 10 AI Prompts to Review and Improve Java Code Quality.

What Context Actually Matters for Hibernate Prompts

Hibernate bugs are context-sensitive in a way most bugs are not. A LazyInitializationException that appears in a REST controller usually has a different root cause than one that appears in a scheduled job — even with identical entity mappings. To get useful output from these prompts, always include three things: your entity classes (not just the one that threw the exception, but the full hierarchy involved), your service or controller code where the exception surfaced, and your Hibernate-relevant application.yml properties (specifically open-in-view, ddl-auto, and any dialect settings).

Specify your JPA provider version — Hibernate 6.x (Spring Boot 3.x) differs from Hibernate 5.x in UUID type mapping, the Criteria API, and HibernateJpaVendorAdapter defaults. A prompt that doesn’t anchor to a version will produce code that may not compile against your actual dependency.

Prompt 1: Design Entity Relationships

When to use: You are modelling a new domain and need help choosing the correct JPA relationship type, fetch strategy, cascade type, and join column configuration — the four decisions that most frequently lead to production performance problems when made incorrectly up front.

Design JPA entity relationships for the following domain model.

Domain description:
[DESCRIBE THE DOMAIN, e.g. "An e-commerce system with Customers, Orders, OrderItems, Products, and Addresses. A Customer has many Orders. An Order has many OrderItems. Each OrderItem references one Product. A Customer has a billing Address and a list of shipping Addresses."]

Database: [e.g. PostgreSQL 16]
JPA provider: [e.g. Hibernate 6.4 / Spring Boot 3.2]

For each relationship, generate the entity mappings with:
1. The correct @OneToMany / @ManyToOne / @ManyToMany / @OneToOne annotation
2. The correct fetch type:
   - @OneToMany and @ManyToMany: always LAZY (the safe default — explain why EAGER is dangerous for collections)
   - @ManyToOne and @OneToOne: EAGER is acceptable only for mandatory, small associations — otherwise LAZY
3. The correct cascade type:
   - Use CascadeType.ALL only on the "owns" side of a parent-child relationship (Order owns OrderItems)
   - Never use CascadeType.REMOVE on @ManyToMany (would delete shared entities)
4. Bidirectional relationship management:
   - On the @OneToMany side: mappedBy = "[inverse field name]", no @JoinColumn
   - Add addItem()/removeItem() helper methods on the parent that maintain both sides
5. orphanRemoval = true on parent-child collections where a child cannot exist without the parent
6. @Column constraints: nullable, unique, length, precision/scale for all fields
7. @Index annotations on frequently queried foreign key columns

Generate the complete entity classes with all annotations. Also generate the matching Flyway V1__init.sql migration script.

Prompt 2: Fix LazyInitializationException

When to use: A LazyInitializationException is thrown — either in a REST controller, a scheduled task, or a unit test — because a lazy-loaded association is accessed after the Hibernate session has closed.

Diagnose and fix the following LazyInitializationException.

Full stack trace:
[PASTE THE FULL EXCEPTION AND STACK TRACE HERE]

Entity class with the lazy association:
[PASTE THE ENTITY CLASS HERE]

Service or controller where the exception occurs:
[PASTE THE SERVICE/CONTROLLER CLASS HERE]

application.yml (Hibernate section):
[PASTE spring.jpa.* properties]

Diagnosis checklist:
1. Is spring.jpa.open-in-view=true in application.yml?
   - If YES: explain why this is an anti-pattern (keeps a DB connection open for the entire HTTP request lifecycle) and how to disable it safely
   - Disabling it will surface LazyInitializationExceptions that were previously hidden — this is a good thing

2. Is the exception thrown because the service method is NOT @Transactional?
   Fix: Add @Transactional(readOnly = true) to the service method so the session stays open while the association is accessed

3. Is the exception thrown AFTER the transaction closed (in a controller or DTO mapper)?
   Fix options (choose based on use case):
   A: Load the association eagerly in the query using JOIN FETCH
   B: Use @EntityGraph on the repository method to eagerly load for this specific call only
   C: Access the association INSIDE the transaction (in the service, before returning the DTO)
   D: Use a DTO projection that fetches only the fields needed (avoids the association entirely)

4. For each fix option, show:
   - The corrected repository method or service method
   - The trade-off (performance, code complexity, query count)

5. Show how to verify the fix using Hibernate's SQL logging:
   spring.jpa.show-sql=true
   spring.jpa.properties.hibernate.format_sql=true

Prompt 3: Write Efficient JPQL and @Query Methods

When to use: Spring Data’s derived query methods (findByStatusAndCreatedAtAfter) have become unreadable, you need aggregations or projections, or you want to ensure a query uses JOIN FETCH correctly to avoid N+1 loading.

Write optimised JPQL @Query methods for the following Spring Data JPA repository.

Entity classes involved:
[PASTE ALL RELEVANT ENTITY CLASSES HERE]

Repository interface:
[PASTE YOUR REPOSITORY INTERFACE HERE]

Queries to write (describe each in plain English):
[LIST YOUR QUERY REQUIREMENTS, e.g.:
1. Find all orders for a customer that are in PENDING or CONFIRMED status, ordered by createdAt DESC, eagerly loading the items collection
2. Find all orders placed in the last 30 days with total value above a threshold, return only id + total + customerEmail (projection)
3. Count orders grouped by status for a dashboard summary
4. Update all PENDING orders older than 7 days to EXPIRED status in a single UPDATE statement (not a per-entity loop)
5. Find the top 5 products by order count in the last 30 days]

For each query:
1. Write the @Query JPQL (and the native SQL version if JPQL cannot express it)
2. For queries that load associations: use JOIN FETCH and explain why
3. For projection queries: create a Java record or interface projection with only the needed fields
4. For bulk UPDATE/DELETE: add @Modifying + @Transactional on the repository method and explain the first-level cache invalidation risk
5. Add pagination support (@Pageable parameter) for any query that may return large result sets
6. Add @QueryHints for read-only queries: @QueryHint(name = HINT_READONLY, value = "true") — prevents dirty checking overhead

Also generate the corresponding @DataJpaTest tests for each query method.

Prompt 4: Generate Flyway Migration Script from Entity Changes

When to use: You have modified JPA entity classes — added a column, changed a relationship, renamed a field, added an index — and need a correct Flyway migration script that handles the schema change safely without data loss, including production-safe defaults for new NOT NULL columns.

Generate a Flyway migration script for the following JPA entity changes.

Database: [e.g. PostgreSQL 16]
Current Flyway version: [e.g. V12]
New migration version: [e.g. V13]

Entity changes made (paste the before and after versions of each changed entity):

BEFORE:
[PASTE THE OLD ENTITY CLASS(ES)]

AFTER:
[PASTE THE NEW ENTITY CLASS(ES)]

For each change, generate the correct SQL and flag any production risk:

1. New nullable column: straight ALTER TABLE ADD COLUMN — safe
2. New NOT NULL column WITHOUT a default: DANGEROUS — will fail on non-empty tables
   Fix: Step 1: ADD COLUMN nullable, Step 2: UPDATE to set a default, Step 3: ALTER to NOT NULL
3. Column rename: RENAME COLUMN — simple but requires ALL queries referencing old name to be updated first
4. Column type change (e.g., VARCHAR(100) → VARCHAR(255)): usually safe to widen; NEVER shrink without data check
5. New unique constraint on existing data: risks failure if duplicates exist
   Fix: Add a query to check for duplicates before the migration, with a comment explaining what to do if found
6. New index: safe online if database supports CONCURRENTLY (PostgreSQL): CREATE INDEX CONCURRENTLY
7. Foreign key addition: safe if all existing rows satisfy the constraint; add with NOT VALID first, then VALIDATE separately for large tables
8. Table rename: most dangerous — requires application code + all migrations to be updated atomically

Output:
- Complete V[N]__[description].sql migration script
- A rollback script V[N]__rollback.sql
- A checklist of application code changes required alongside this migration

Prompt 5: Configure Hibernate Second-Level Cache

When to use: A read-heavy entity (product catalogue, configuration, reference data) is being loaded from the database on every request, and you want to configure Hibernate’s second-level cache with Redis or Ehcache to serve repeated reads from memory without changing your service layer code.

Configure Hibernate second-level cache for the following entities using [Redis / Ehcache].

Cache backend: [Redis via Redisson / Ehcache 3]
JPA provider: Hibernate 6.x (Spring Boot 3.x)

Entities to cache:
[LIST ENTITIES AND THEIR ACCESS PATTERN, e.g.:
- Product: read-heavy (thousands of reads/minute), updated rarely (once per hour max), TTL 30 minutes
- Category: almost never updated, TTL 24 hours
- OrderStatus (enum-like): never updated after deploy, TTL indefinitely
- Order: do NOT cache — updated frequently, inconsistency would cause data integrity issues]

Generate:
1. Maven/Gradle dependencies for the chosen cache provider
2. application.yml entries:
   - spring.jpa.properties.hibernate.cache.use_second_level_cache=true
   - spring.jpa.properties.hibernate.cache.region.factory_class=[provider class]
   - Per-entity TTL configuration
3. @Cache annotation on each entity class:
   - Usage.READ_WRITE for entities that can be updated
   - Usage.READ_ONLY for immutable/near-immutable entities (faster, no locking overhead)
   - Usage.NONSTRICT_READ_WRITE when stale reads are acceptable for a short window
4. @Cache on @OneToMany collections that should also be cached:
   - Explain when collection caching helps vs when it causes more cache invalidation overhead
5. Cache eviction: show how to programmatically evict a specific entity from cache:
   entityManager.getEntityManagerFactory().getCache().evict(Product.class, productId);
6. Monitoring: show how to enable Hibernate cache statistics logging to verify cache hit/miss ratio
7. A @SpringBootTest that verifies the second-level cache is being used:
   - Calls findById twice for the same entity
   - Verifies the database is queried only once (use Hibernate statistics)

Prompt 6: Optimise Bulk Insert and Update Operations

When to use: A batch job, data import, or event consumer is persisting thousands of entities and is either extremely slow or causing out-of-memory errors because the Hibernate first-level cache is accumulating every entity in memory for the duration of the session.

Optimise the following Hibernate bulk operation for performance and memory efficiency.

Current code (paste the service method performing the bulk operation):
[PASTE YOUR BULK OPERATION CODE HERE]

Entity class:
[PASTE THE ENTITY CLASS HERE]

Operation type: [INSERT / UPDATE / DELETE / MIXED]
Approximate volume: [e.g. 50,000 records per batch run]
Database: [e.g. PostgreSQL]

Performance problems to fix:

1. JDBC batch INSERT not enabled:
   Add to application.yml:
   spring.jpa.properties.hibernate.jdbc.batch_size=50
   spring.jpa.properties.hibernate.order_inserts=true
   spring.jpa.properties.hibernate.order_updates=true
   Explain why IDENTITY generation strategy disables batching and how to switch to SEQUENCE

2. First-level cache accumulation (OutOfMemoryError risk):
   Current: for (Entity e : bigList) { em.persist(e); } — all 50,000 entities stay in session cache
   Fix: Flush and clear every batch_size entities:
   if (count % BATCH_SIZE == 0) { em.flush(); em.clear(); }

3. For UPDATES: consider a single JPQL bulk update instead of loading and modifying each entity:
   @Modifying @Query("UPDATE Product p SET p.price = p.price * :multiplier WHERE p.category = :category")
   — this bypasses the first-level cache entirely; show how to evict stale cached entities after

4. For PostgreSQL: consider using INSERT ... ON CONFLICT DO UPDATE (upsert) for idempotent imports:
   Show the native @Query with nativeQuery=true

5. For very large volumes (>500K rows): show Spring Batch JpaPagingItemReader + JpaItemWriter pattern
   — processes in configurable chunks, restartable, progress-trackable

6. Show the Hibernate statistics configuration to measure batch efficiency:
   Queries executed before and after optimisation for the same dataset size

Prompt 7: Implement Soft Delete

When to use: Business requirements demand that deleted records are retained in the database for auditing or recovery, but you want deletions to be transparent to the rest of the application — service methods and queries should automatically exclude soft-deleted records without manual WHERE deleted = false conditions everywhere.

Implement soft delete for the following JPA entity using Hibernate's @SQLRestriction (Hibernate 6.3+) or @Where (Hibernate 5.x).

Entity to add soft delete to:
[PASTE YOUR ENTITY CLASS HERE]

Other entities that have @OneToMany or @ManyToMany relationships pointing to this entity:
[PASTE RELATED ENTITY CLASSES HERE]

Hibernate version: [6.3+ (use @SQLRestriction) / 5.x (use @Where)]

Generate:
1. Updated entity with:
   - deleted boolean field (NOT NULL DEFAULT false) with @Column(name="deleted")
   - deletedAt LocalDateTime field (nullable)
   - deletedBy String field (nullable, stores the username that performed the soft delete)
   - @SQLRestriction("deleted = false") on the entity class (Hibernate 6.3+)
     OR @Where(clause = "deleted = false") for Hibernate 5.x

2. SoftDeleteRepository interface:
   - Override delete(T entity) to set deleted=true and deletedAt=now() instead of issuing DELETE SQL
   - Add findAllIncludingDeleted() method that bypasses the soft delete filter (for admin endpoints)
   - Add restoreById(Long id) method

3. @SQLRestriction on collection mappings:
   - When a parent entity has @OneToMany pointing to this entity, the restriction must be applied to the collection mapping too — show the @SQLJoinTableRestriction syntax

4. Audit trail: show how to combine soft delete with Spring Data Auditing (@CreatedDate, @LastModifiedDate, @CreatedBy, @LastModifiedBy)

5. Database index: add a partial index on the non-deleted rows for query performance:
   CREATE INDEX idx_[entity]_active ON [table](id) WHERE deleted = false;

6. Flyway migration script to add the new columns to an existing table with safe defaults

7. A @DataJpaTest that verifies:
   - A soft-deleted entity is not returned by findAll()
   - The entity IS returned by findAllIncludingDeleted()
   - restore() correctly sets deleted=false

Prompt 8: Implement Auditing with @EntityListeners

When to use: You need to automatically track who created or last modified every entity, and when — without adding boilerplate to every service method. Spring Data’s auditing support handles this transparently using JPA entity listeners.

Implement JPA auditing for all entities in this Spring Boot 3.x application.

Entities to audit:
[PASTE YOUR ENTITY CLASSES HERE]

Auditing requirements:
- createdAt: timestamp when the record was first persisted
- updatedAt: timestamp whenever the record is updated
- createdBy: username of the authenticated user who created the record
- updatedBy: username of the authenticated user who last modified the record
- Audit fields should be read-only after creation (createdAt, createdBy must not be overwritten on update)

Generate:
1. Auditable base class (MappedSuperclass):
   @MappedSuperclass
   @EntityListeners(AuditingEntityListener.class)
   public abstract class Auditable {
     // @CreatedDate, @LastModifiedDate, @CreatedBy, @LastModifiedBy fields
     // All with @Column(updatable = false/true as appropriate)
   }

2. AuditorAware<String> @Bean:
   - Extract the current username from Spring Security's SecurityContextHolder
   - Return "SYSTEM" when no authentication is present (batch jobs, startup tasks)
   - Handle the case where the Authentication principal is a UserDetails object vs a plain String

3. Enable JPA Auditing: @EnableJpaAuditing(auditorAwareRef = "auditorProvider") on a @Configuration class

4. Update the entity classes to extend Auditable (show the change for each entity)

5. Flyway migration: ALTER TABLE statements to add the four audit columns to each existing table

6. A @DataJpaTest that verifies:
   - createdAt and createdBy are set on persist
   - updatedAt is updated on merge
   - createdAt and createdBy are NOT changed on update

7. Bonus: show how to add a full audit log table (every change as a row) using Hibernate Envers:
   - @Audited annotation on the entity
   - AuditReader to query the revision history
   - The Flyway migration for the _AUD table Envers creates

Prompt 9: Convert Native SQL to Type-Safe Criteria API

When to use: A codebase has accumulated native SQL queries that are brittle, not refactor-safe, and cannot be composed dynamically. You want to migrate them to the JPA Criteria API (or a simpler Spring Data Specification) for type safety and dynamic query construction.

Convert the following native SQL queries to JPA Criteria API Specifications for use with Spring Data JPA.

Entity and its metamodel:
[PASTE YOUR ENTITY CLASS HERE]

Native SQL queries to convert:
[PASTE THE NATIVE SQL QUERIES HERE, e.g.:
SELECT * FROM orders o
JOIN customers c ON c.id = o.customer_id
WHERE o.status IN ('PENDING', 'CONFIRMED')
AND o.created_at >= :startDate
AND (c.email LIKE :emailPattern OR c.name LIKE :namePattern)
AND o.total_amount BETWEEN :minAmount AND :maxAmount
ORDER BY o.created_at DESC]

For each query, generate:
1. A Specification<Entity> class:
   - One static factory method per predicate (e.g., Specifications.withStatus(Set<Status> statuses))
   - Null-safe: if the parameter is null, return a conjunction (no-op predicate) so the filter is simply skipped
   - Type-safe using the JPA metamodel (Order_.status, not string literal "status")

2. How to combine Specifications:
   Specification<Order> spec = Specification
     .where(withStatus(filter.getStatuses()))
     .and(createdAfter(filter.getStartDate()))
     .and(customerEmailOrNameContains(filter.getSearchTerm()))
     .and(totalAmountBetween(filter.getMinAmount(), filter.getMaxAmount()));

3. Repository method:
   - Extend JpaSpecificationExecutor<Entity>
   - Use findAll(spec, pageable) for paginated results

4. OrderFilterRequest record — the DTO carrying all the optional filter parameters

5. Show how to generate the JPA metamodel with the hibernate-jpamodelgen annotation processor in Maven

6. A @DataJpaTest verifying that each Specification filters correctly

Prompt 10: Full JPA Entity Model Review

When to use: You are inheriting a Hibernate-based codebase, preparing for a major release, or onboarding to a module and want a comprehensive review of the entity model for mapping mistakes, performance anti-patterns, and missing constraints before they cause problems in production.

Perform a comprehensive JPA entity model review for the following entity classes.

Entity classes (paste all of them):
[PASTE ALL ENTITY CLASSES HERE]

Repository interfaces:
[PASTE REPOSITORY INTERFACES HERE]

application.yml (Hibernate section):
[PASTE spring.jpa.* AND spring.datasource.* properties]

Review checklist — evaluate every item:

MAPPING CORRECTNESS:
[ ] @Id strategy: is IDENTITY used? (disables JDBC batching in Hibernate) — flag and suggest SEQUENCE
[ ] @Column(nullable=false) matches NOT NULL constraint in DB schema?
[ ] @Column(unique=true) creates a UK constraint — is there a matching @Index?
[ ] @JoinColumn foreign key columns — are they indexed?
[ ] @Enumerated(EnumType.STRING) used? (ORDINAL is fragile — breaks if enum values are reordered)
[ ] Are all bidirectional relationships maintained on both sides (addItem helper methods)?

FETCH STRATEGY:
[ ] Any @OneToMany(fetch=EAGER) → flag as dangerous, explain why, suggest JOIN FETCH instead
[ ] Any @ManyToMany(fetch=EAGER) → flag as very dangerous (Cartesian product risk)
[ ] Any @OneToOne that could be LAZY — is it mapped with @LazyToOne(NO_PROXY)?

PERFORMANCE:
[ ] Large @Lob fields (CLOB, BLOB) on frequently queried entities — should be in a separate table
[ ] Collections accessed outside a transaction (LazyInitializationException risk)
[ ] spring.jpa.open-in-view=true — flag and recommend disabling

SCHEMA SAFETY:
[ ] spring.jpa.hibernate.ddl-auto=update or create-drop in a non-dev environment — CRITICAL flag
[ ] Missing @Table(name="...") — relying on Hibernate's naming convention (breaks if naming strategy changes)
[ ] Missing @Version for entities with optimistic locking requirements

For each finding: severity, entity class, annotation or property, risk description, and the fix.

Tips for Better Hibernate Results

  • Always specify your Hibernate version. The @SQLRestriction annotation (Prompt 7) was introduced in Hibernate 6.3 and replaces the deprecated @Where. The Criteria API and metamodel generation also changed between Hibernate 5 and 6. Specifying the version prevents the AI from generating code that will not compile against your dependency.
  • Enable Hibernate SQL logging during development. Add spring.jpa.show-sql=true and spring.jpa.properties.hibernate.format_sql=true while working on any of these prompts. The AI’s suggested fixes often reduce query counts dramatically — seeing the before/after SQL confirms the change worked.
  • Never use ddl-auto=update in production. Every prompt that generates entity changes also generates a Flyway migration. Use the migration exclusively — do not rely on Hibernate’s DDL auto-update to modify a production database schema.

Frequently Asked Questions (FAQs)

Q1: Can I use these prompts with Spring Data JDBC instead of JPA?

Prompts 3, 6, and 9 are largely transferable because they focus on query patterns and bulk operations. Prompts 1, 2, 4, 5, 7, 8, and 10 are JPA/Hibernate-specific. If you are using Spring Data JDBC, replace the prompt context with: “Using Spring Data JDBC (not JPA/Hibernate) — no entity managers, no sessions, no lazy loading.” Spring Data JDBC’s simpler aggregate model means Prompts 2 and 5 do not apply at all, which is by design.

Q2: Prompt 6 mentions switching from IDENTITY to SEQUENCE for batching. Is that always necessary?

Only for entities being inserted in large bulk operations. If you are inserting 10–100 entities per transaction, the batching benefit of SEQUENCE over IDENTITY is negligible. The switch becomes worthwhile when inserting 1,000+ entities per transaction — at that scale, the IDENTITY strategy’s inability to batch can reduce throughput by 10x. For PostgreSQL, @GeneratedValue(strategy=SEQUENCE) with an allocation size of 50 is the recommended production default regardless of bulk operations.

Q3: Is the @SQLRestriction (soft delete) applied to JOIN queries too?

Yes — @SQLRestriction is applied to every HQL/JPQL query and every lazy/eager collection load for that entity type. However, it is NOT applied to native SQL queries written with @Query(nativeQuery = true). For native queries, you must add the WHERE deleted = false condition manually. This is one reason to prefer JPQL over native SQL in codebases that use soft delete.

Q4: How do I test queries that use @SQLRestriction?

Use @DataJpaTest with an H2 in-memory database. Insert both active and soft-deleted records using TestEntityManager, then verify that the repository methods only return active records. To test findAllIncludingDeleted(), use a @NativeQuery or call entityManager.createNativeQuery() which bypasses the @SQLRestriction filter — or use the @Filter mechanism with explicit session-level filter disabling for more control.

See Also

Conclusion

These 10 prompts address the full range of practical Hibernate and JPA challenges: designing entity relationships correctly from the start, fixing LazyInitializationException, writing efficient JPQL, generating safe Flyway migrations, configuring second-level caching, optimising bulk operations, implementing soft delete and auditing, converting SQL to Specifications, and auditing an entire entity model. The combination of your domain knowledge and AI’s fluency with the JPA specification and Hibernate internals produces faster, more reliable results than either approach alone — particularly for the subtle trade-offs around fetch strategies, cascade types, and cache invalidation that the documentation describes but rarely contextualises for a real production system.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.