Technology Aug 23, 2026 · 2 min read

Stop Killing Your Database with @Transactional in Spring Boot

The 1-minute fix that slashed my API response time by 40%. We all know @Transactional makes database work easy. But are you using it correctly? Here is a mistake I see in 8 out of 10 code reviews: ❌ The Anti-Pattern: @Service public class OrderService { @Transactional public...

DE
DEV Community
by Sayuri Kotikawaththa
Stop Killing Your Database with @Transactional in Spring Boot

The 1-minute fix that slashed my API response time by 40%.

We all know @Transactional makes database work easy. But are you using it correctly?

Here is a mistake I see in 8 out of 10 code reviews:

❌ The Anti-Pattern:

@Service
public class OrderService {
    @Transactional
    public Order placeOrder(OrderDto dto) {
        Order order = new Order();
        // 1. Save the parent
        orderRepository.save(order);

        // 2. Loop and save children one by one
        for (Item i : dto.getItems()) {
            Item item = new Item();
            item.setOrder(order);
            itemRepository.save(item); // 💀 N+1 problem + multiple flush calls
        }
        return order;
    }
}

The Problem: Even with @Transactional, calling .save() in a loop forces Hibernate to hit the database for every single item. That’s 50 round trips for 50 items.

✅ The Game-Changer:
Use Batch Insertion with a simple property change.

1.Add this to application.properties:

spring.jpa.properties.hibernate.jdbc.batch_size=50
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true

2.Refactor your code to use .saveAll():

@Transactional
public Order placeOrder(OrderDto dto) {
    Order order = new Order();
    orderRepository.save(order); // Save parent first

    List<Item> items = dto.getItems().stream()
        .map(i -> new Item(i, order))
        .collect(Collectors.toList());

    itemRepository.saveAll(items); // ONE single INSERT statement for all items!

    return order;
}

The Result:

  • Before: 51 SQL queries for 50 items.
  • After: 2 SQL queries for 50 items.
  • Performance: 40% faster response time.
  • DB Load: Drastically reduced.

The takeaway: @Transactional manages the transaction, but it doesn't batch your queries. You have to explicitly tell Hibernate to batch them.

Discussion Question: What's the one Spring Boot property you can't live without? Drop it in the comments! 👇

DE
Source

This article was originally published by DEV Community and written by Sayuri Kotikawaththa.

Read original article on DEV Community
Back to Discover

Reading List