Environment
- JDK 21
- Spring Boot 3.4.6 + 3.5.0
- PostgreSQL 16.9 (installed with Homebrew)
- macOS 15.5
Reproducible code
https://github.com/MasatoshiTada/transaction-timeout-sample-jdbc/blob/main/src/test/java/com/example/transactiontimeoutsamplejdbc/SampleServiceTest.java
What happens
My repository class:
@Repository
public class SampleRepository {
private final JdbcTemplate jdbcTemplate;
public SampleRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public List<Sample> selectAll() {
return jdbcTemplate.query("SELECT id, name FROM sample ORDER BY id", new DataClassRowMapper<>(Sample.class));
}
public Object sleep(int seconds) {
return jdbcTemplate.queryForObject("SELECT pg_sleep(?)", new Object[]{seconds}, Object.class);
}
public void insert(Sample sample) {
jdbcTemplate.update("INSERT INTO sample(id, name) VALUES (?, ?)", sample.id(), sample.name());
}
}
My service class. registerWithSleep()
will timed out in 2 seconds.
@Service
public class SampleService {
private static final Logger logger = LoggerFactory.getLogger(SampleService.class);
private final SampleRepository sampleRepository;
public SampleService(SampleRepository sampleRepository) {
this.sampleRepository = sampleRepository;
}
@Transactional(timeout = 2, readOnly = false)
public void registerWithSleep(Sample sample, int seconds) {
logger.info("Sleep {}seconds...", seconds);
sampleRepository.sleep(seconds);
logger.info("Sleep completed. Starting INSERT...");
sampleRepository.insert(sample) ;
logger.info("INSERT completed.");
}
}
This method times out in 2 seconds as I expected, but throws DataAccessResourceFailureException
.
Expected behavior
TransactionTimedOutException
is thrown.
Why does it behave like this?
When the transaction times out, PostgreSQL returns the SQL state "57014" (query_cancelled).
PostgreSQL JDBC Driver cancells a query with
TimerTask
(see here)
Since sql-error-codes.xml does not contain "57014", Spring fallbacks to SQLStateSQLExceptionTranslator
that has "57" (DB2: out-of-memory exception / database not started) in DATA_ACCESS_RESOURCE_FAILURE_CODES
.