Java Backend Interview Q&A← All stacks

Spring Data JPA & Hibernate — Interview Q&A Matrix

Parent stack: Spring Ecosystem Technology: Spring Data JPA & Hibernate Levels: Junior · Senior · Architect Questions: 4

Each entry contains a Question, the Expected Depth, an Ideal Answer, and Red Flags.

Junior

Q1 — Spring Data JPA repositories

Question: How do Spring Data JPA repositories work, and how would you fetch active users by email domain?

Expected Depth:

Ideal Answer:

java
public interface UserRepository extends JpaRepository<User, Long> {
    List<UserSummary> findByActiveTrueAndEmailEndingWithIgnoreCase(
            String domainSuffix);

    @Query("""
        select new com.example.UserSummary(u.id, u.email)
        from User u
        where u.active = true
          and lower(u.email) like lower(concat('%@', :domain))
        order by u.email
        """)
    List<UserSummary> findActiveByDomain(@Param("domain") String domain);
}
java
public record UserSummary(Long id, String email) {}
java
Page<UserSummary> findByActiveTrue(Pageable pageable);

Red Flags:


Senior

Q2 — Solving the N+1 query problem

Question: A list endpoint issues one query for orders then one per order for its line items. Diagnose and fix the N+1 problem while avoiding a Cartesian explosion.

Expected Depth:

Ideal Answer:

java
@Query("""
    select distinct o
    from Order o
    left join fetch o.items
    where o.status = :status
    """)
List<Order> findWithItems(@Param("status") Status status);
java
@Query("""
    select o.id from Order o
    where o.status = :status
    order by o.createdAt desc
    """)
Page<Long> findPageIds(
        @Param("status") Status status,
        Pageable pageable);

@Query("""
    select distinct o from Order o
    left join fetch o.items
    where o.id in :ids
    """)
List<Order> findWithItemsByIdIn(Collection<Long> ids);
properties
spring.jpa.properties.hibernate.default_batch_fetch_size=50
properties
spring.jpa.open-in-view=false

Red Flags:


Q3 — Optimistic locking & concurrent updates

Question: Two users update the same account balance concurrently and one overwrites the other (lost update). How do you prevent this with JPA?

Expected Depth:

Ideal Answer:

java
@Entity
class Account {
    @Id
    private Long id;

    @Version
    private long version;

    private BigDecimal balance;
}
java
public interface AccountRepository extends JpaRepository<Account, Long> {
    @Lock(LockModeType.PESSIMISTIC_WRITE)
    @Query("select a from Account a where a.id = :id")
    Optional<Account> findForUpdate(@Param("id") Long id);
}
java
@Modifying(clearAutomatically = true, flushAutomatically = true)
@Query("""
    update Account a
    set a.balance = a.balance - :amount,
        a.version = a.version + 1
    where a.id = :id and a.balance >= :amount
    """)
int debitIfEnoughFunds(
        @Param("id") Long id,
        @Param("amount") BigDecimal amount);

Red Flags:


Architect

Q4 — Persistence architecture: read/write splitting and CQRS boundaries

Question: A read-heavy platform saturates the primary DB. Design a persistence architecture using Spring that scales reads without sacrificing consistency where it matters.

Expected Depth:

Ideal Answer:

java
public class RoutingDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return TransactionSynchronizationManager.isCurrentTransactionReadOnly()
                ? "replica"
                : "primary";
    }
}
text
Primary transaction -> outbox event -> projector -> read model

Red Flags:


Scoring Rubric

Level Pass bar
JuniorUses repositories, parameters, projections, and paging correctly.
SeniorDiagnoses query and concurrency problems and fixes them with safe transaction boundaries.
ArchitectDesigns replica and CQRS strategies with explicit consistency and recovery rules.