How to Optimize Large Transactions in API Endpoints

The article examines why large database transactions inside API endpoints degrade performance, outlines issues such as data inconsistency, lock contention, undo‑log overhead, and DB pressure, and presents practical optimizations including removing remote RPC calls, using programmatic transactions, batch processing, splitting into smaller transactions, and asynchronous parallel execution with code examples.

Architect's Guide
Architect's Guide
Architect's Guide
How to Optimize Large Transactions in API Endpoints

1. Introduction

Backend developers often place complex business logic—queries, remote or local service calls, updates, inserts, calculations—into a single API endpoint. Because the whole operation runs inside a database transaction, each DB interaction creates a transaction record, which can significantly slow the interface response, especially as data volume grows. Splitting a large transaction can improve overall efficiency.

2. What Is a Large Transaction?

The author describes a recent interface that generates a receivable document based on user‑submitted data. All steps—validation, third‑party calls, status updates, and calculations—are written in one method, making it a large transaction that takes a long time to execute and is not a reasonable design.

Diagram
Diagram

3. Problems Caused by Large Transactions

Concurrent Data Inconsistency

Without locking, a second request may modify data while the first request is still waiting for a third‑party response. When the first request finally writes back its result, the data may have already been updated, leading to invalid operations.

Locking Leads to Blocking

Locking prevents inconsistency but, because the transaction runs for a long time, locks may time out or block other operations, severely affecting efficiency.

Undo‑Log Performance Issues

The undo log can become very large, degrading log query performance and slowing transaction rollback.

High Database Pressure

When concurrency reaches a certain level, the database experiences heavy read/write load and many threads wait, reducing throughput.

4. Optimizing Large Transactions

Avoid Remote RPC Calls Inside Transactions

Embedding remote service calls in a transaction without a distributed‑transaction framework can cause inconsistency and makes rollback impossible. Asynchronous calls are required when remote calls cannot be avoided.

Programmatic Transactions Offer More Flexibility

Declarative @Transactional applies to the whole method, including read operations that need not be transactional. Using programmatic transactions (TransactionTemplate) allows selective transaction boundaries around update/insert operations.

public Boolean transactionCommit(String userName) {
    // query user
    SysUser sysUser = userMapper.selectUserByUserName(userName, null);

    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
        @Override
        protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
            try {
                if (null != sysUser) {
                    // update status to 1
                    userMapper.updateStatus(userName);
                }
            } catch (Exception e) {
                // rollback
                transactionStatus.setRollbackOnly();
            }
        }
    });
    // query again
    SysUser sysUser1 = userMapper.selectUserByUserName(userName, "1");
    log.info("状态为1的用户信息" + JSON.toJSONString(sysUser1));
    return true;
}

The flexibility comes from controlling which operations participate in the transaction; read queries can be placed outside the MySQL transaction table.

Batch Processing of Data

When the front end submits bulk updates or inserts, a failure in any item forces the whole transaction to roll back. To mitigate this, both front‑end and back‑end can paginate the data.

Front end: limit the number of records per request, sending multiple paged requests.

Back end: process data in batches, e.g., 50 records per batch, using MyBatis batch updates to improve efficiency.

List<List<ReceivableFeeSaveDTO>> partition = Lists.partition(receivableFeeSaveDTOList, 50);

Split Large Transaction into Smaller Ones

Break the monolithic endpoint into several smaller endpoints, each handling a single responsibility such as amount write‑back, third‑party call, or result persistence. This mirrors decomposing a complex task into sequential steps.

Asynchronous Parallel Processing

If remote calls cannot be avoided, execute them asynchronously. CompletableFuture enables parallel execution of independent tasks and combines their results before the final write‑back.

CompletableFuture<Object> task1 = CompletableFuture.supplyAsync(() -> {
    System.out.println("单号check线程" + Thread.currentThread().getId());
    // validation logic
    return "账单实体信息";
}, executor);

CompletableFuture<Object> task2 = CompletableFuture.supplyAsync(() -> {
    System.out.println("收款单生成线程" + Thread.currentThread().getId());
    try {
        // generate receivable
        return "账单编号";
        Thread.sleep(3000);
        System.out.println("任务2结束:");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return null;
}, executor);

// After task1 and task2 finish, execute task3, using both results
CompletableFuture<Boolean> future = task1.thenCombineAsync(task2, (t1, t2) -> {
    System.out.println("账单金额回写线程" + Thread.currentThread().getId());
    // combine results and write back
    return true;
}, executor);

5. Conclusion

Large transactions are a primary cause of poor API performance. While quick implementations may overlook performance considerations, recognizing and addressing these issues—by removing unnecessary RPC calls, using programmatic transactions, batching, splitting, and asynchronous execution—provides an opportunity for skill growth and more maintainable code.

Diagram
Diagram
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Backend DevelopmentBatch Processingasynchronous processingtransactionsprogrammatic transaction
Architect's Guide
Written by

Architect's Guide

Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.