patternjavaspringTip
Spring Data JPA: @Transactional(readOnly=true) improves read performance
Viewed 0 times
readOnly transactiondirty checkingHibernate performance@Transactional readOnlyread replica routingflush
Problem
All Spring Data repository methods run in a transaction by default. Read-only operations that load entities carry the overhead of Hibernate's dirty checking — comparing every loaded entity's state to a snapshot on transaction commit — even though no writes will occur.
Solution
Annotate read-only service methods with @Transactional(readOnly=true):
For Spring Data repositories, override with readOnly on the service layer rather than the repository layer to keep service semantics clear. readOnly=true also signals to the database driver (and some connection pools) that the transaction does not write, enabling routing to read replicas.
@Service
public class OrderQueryService {
@Transactional(readOnly = true)
public List<OrderSummary> getOrderSummaries(Long userId) {
return orderRepo.findSummariesByUserId(userId);
}
@Transactional(readOnly = true)
public Optional<Order> getOrderWithItems(Long orderId) {
return orderRepo.findWithItemsById(orderId);
}
}For Spring Data repositories, override with readOnly on the service layer rather than the repository layer to keep service semantics clear. readOnly=true also signals to the database driver (and some connection pools) that the transaction does not write, enabling routing to read replicas.
Why
readOnly=true calls Session.setDefaultReadOnly(true) in Hibernate, which disables dirty checking for all loaded entities. This skips the snapshot comparison phase at commit time, reducing memory and CPU overhead for large read operations.
Gotchas
- readOnly=true does not prevent writes from happening — it is a hint, not a constraint, at the JPA level
- Some databases use readOnly to route to replicas — ensure replica lag is acceptable for the use case
- Modifying a readOnly transaction entity does not throw an exception in Hibernate; it silently skips the flush
Revisions (0)
No revisions yet.