SkillByAIOpen interactive version →

Lesson 13 / 25

Transactions and Open Session in View

Consistent writes, explicit boundaries.

@Transactional on services

@Transactional on service methods makes their database work atomic: everything commits together or rolls back on a runtime exception. readOnly = true lets the driver and Hibernate optimise reads. Put transactions in the service layer, not controllers. Disable open session in view (spring.jpa.open-in-view=false, as the demo does) so lazy loading cannot silently run queries during JSON rendering outside transactions; Spring Boot warns when it is left enabled.

Transactional service methods

This file is from a demo "shop" service generated by start.spring.io for Spring Boot 4.1.1 and Java 21 (Temurin 21.0.12), built with Maven 3.9.16; the project compiled and its tests passed. Reads are read-only transactions; create runs in a read-write transaction (the same file as the injection example).

import org.springframework.transaction.annotation.Transactional;
public class ProductService {
    public ProductService(ProductRepository repository) {   // constructor injection
    @Transactional(readOnly = true)
    public Product get(long id) {
    @Transactional(readOnly = true)
    public List<Product> cheaperThan(BigDecimal max) {
    @Transactional
    public Product create(String name, BigDecimal price) {

Beware self-invocation

@Transactional works through proxies, so calling a transactional method from inside the same class bypasses it.

Quick check: Where should @Transactional usually be placed?

  • On JSON DTO records
  • On service-layer methods that define a unit of work
  • On the main method
  • On every getter
Answer

On service-layer methods that define a unit of work — Services own transaction boundaries.