venkatesh
№032 · JUL 16, 2026 · 3 MIN READ

One @Transactional Annotation Doubled Our API Latency

We added one annotation. Our API latency doubled. 💀

No slow SQL. No missing indexes. No traffic spike. Just one innocent-looking @Transactional.

Long transaction holding a database connection versus a short transaction

@Transactional
public void updateOrder() {
    Order order = repository.findById(id);
    paymentService.verifyPayment(); // ~800ms
    repository.save(order);
}

At first glance, nothing looked wrong. But the transaction starts before the external API call.

That means:

  • A database connection is acquired.
  • The transaction stays open while waiting about 800 ms for another service.
  • That connection can’t return to the pool.

At low traffic, nobody notices. At production scale, hundreds of requests hold database connections far longer than necessary.

The result:

  • Connection-pool exhaustion
  • Requests waiting for available connections
  • API latency spiking across the system

The database wasn’t slow. The queries weren’t slow. We were holding an expensive resource for too long.

The fix was surprisingly simple:

External API call
        ↓
@Transactional
fetch → update → save

Keep transactions for database work only. @Transactional isn’t just about whether you use it. It’s also about where you use it.

A few extra milliseconds inside a transaction might seem harmless until they’re multiplied across thousands of concurrent requests.

copied!