Boost Spring Boot Throughput: Programmatic Transaction Management vs @Transactional
This article demonstrates how using Spring Boot's TransactionTemplate to programmatically control transactions can prevent long‑running non‑transactional operations from blocking database connections, thereby increasing system throughput compared to the traditional @Transactional annotation, with detailed code examples and performance observations.
Environment: Spring Boot 2.3.9.RELEASE, JPA, MySQL.
Typical usage in a Spring project is to add @Transactional on a method or class, e.g.:
@Transactional
public Account deduction(Long id, BigDecimal money) {
Optional<Account> op = accountDAO.findById(id);
if (!op.isPresent()) {
throw new RuntimeException("不存在");
}
account.setMoney(account.getMoney().subtract(money));
return accountDAO.saveAndFlush(account);
}This method‑level transaction opens a connection, begins a transaction, executes the method, then commits or rolls back.
When the connection pool is limited (e.g., only one connection), long‑running non‑transactional work can occupy the connection and drastically reduce throughput. The article simulates this low‑throughput scenario by configuring the datasource with a single HikariCP connection:
spring:
datasource:
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/x?serverTimezone=GMT%2B8
username: root
password: xxxx
type: com.zaxxer.hikari.HikariDataSource
hikari:
minimumIdle: 1
maximumPoolSize: 1
autoCommit: true
idleTimeout: 30000
poolName: MasterDatabookHikariCP
maxLifetime: 1800000
connectionTimeout: 30000
connectionTestQuery: SELECT 1Service method with a simulated 10‑second delay:
@Transactional
public Account deduction(Long id, BigDecimal money) {
System.out.println("Service 当前执行线程:" + Thread.currentThread().getName() + ", id = " + id + ", money = " + money);
Account account = accountDAO.findById(id).orElse(null);
if (account == null) {
return null;
}
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.setMoney(account.getMoney().subtract(money));
return accountDAO.saveAndFlush(account);
}Controller endpoint:
@GetMapping("/deduction")
public Object deductionAction(Long id, BigDecimal money) {
System.out.println("Controller 当前线程:" + Thread.currentThread().getName());
return accountService.deduction(id, money);
}Testing with two browsers shows that only one service method proceeds because the single connection is held by the transaction, while the other request waits.
To improve throughput, the article replaces the annotation with programmatic transaction control using TransactionTemplate:
@Resource
private TransactionTemplate transactionTemplate;
public Account deduction(Long id, BigDecimal money) {
System.out.println("Service 当前执行线程:" + Thread.currentThread().getName() + ", id = " + id + ", money = " + money);
Account account = accountDAO.findById(id).orElse(null);
if (account == null) {
return null;
}
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Non‑transactional part finished, now execute the DB update in a transaction
return transactionTemplate.execute(status -> {
try {
account.setMoney(account.getMoney().subtract(money));
return accountDAO.saveAndFlush(account);
} catch (Exception e) {
logger.error("发生错误:{}", e);
status.setRollbackOnly();
}
return null;
});
}The @Transactional annotation is removed; only the critical update is wrapped in a transaction. Spring Boot automatically configures TransactionTemplate via TransactionAutoConfiguration.
After redeploying, both browser requests complete even with a single connection pool, because the long‑running computation runs outside the transaction, freeing the connection for other requests. This demonstrates a noticeable increase in system throughput.
Conclusion: By separating time‑consuming non‑transactional logic from the transactional block and using programmatic transaction management, you can avoid connection bottlenecks and improve overall performance.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
