Using Multi‑Catch and Try‑with‑Resources in Java for Database Operations
This article demonstrates how to combine multiple exception types in a single catch block and how to employ Java's try‑with‑resources construct to automatically close resources, providing complete code examples drawn from Nacos's BaseDatabaseOperate class.
The article explains two useful Java techniques for database‑related code: using a multi‑catch block to handle several exceptions in one clause, and leveraging the try‑with‑resources statement (available since JDK 1.7) to ensure resources are closed automatically.
1. Multi‑catch block syntax
Referencing the Nacos nacos-config BaseDatabaseOperate class, the following method shows a typical pattern:
default Boolean update(TransactionTemplate transactionTemplate, JdbcTemplate jdbcTemplate, List<ModifyRequest> contexts, BiConsumer<Boolean, Throwable> consumer) {
try {
return Boolean.TRUE;
} catch (BadSqlGrammarException | DataIntegrityViolationException e) {
FATAL_LOG.error("[db-error] sql : {}, args : {}, error : {}", errSql[0], args[0], e.toString());
return Boolean.FALSE;
}
}When several exceptions require identical handling, the catch (XxxException | YyyException) form keeps the code concise and elegant.
2. Resource closing with try‑with‑resources
Since JDK 1.7, the try‑with‑resources mechanism simplifies resource management. The example below, taken from Nacos's batch‑upload configuration interface, shows how to read a file line‑by‑line while automatically closing the iterator:
try (DiskUtils.LineIterator iterator = DiskUtils.lineIterator(file)) {
int batchSize = 1000;
List<String> batchUpdate = new ArrayList<>(batchSize);
List<CompletableFuture<Void>> futures = new ArrayList<>();
List<Boolean> results = new CopyOnWriteArrayList<>();
while (iterator.hasNext()) {
String sql = iterator.next();
if (StringUtils.isNotBlank(sql)) {
batchUpdate.add(sql);
}
if (batchUpdate.size() == batchSize || !iterator.hasNext()) {
List<ModifyRequest> sqls = batchUpdate.stream().map(s -> {
ModifyRequest request = new ModifyRequest();
request.setSql(s);
return request;
}).collect(Collectors.toList());
futures.add(CompletableFuture.runAsync(() -> results.add(doDataImport(jdbcTemplate, sqls))));
batchUpdate.clear();
}
}
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
return RestResult.<String>builder()
.withCode(BooleanUtils.and(results.toArray(new Boolean[0])) ? 200 : 500)
.withData("")
.build();
} catch (Throwable ex) {
LogUtil.DEFAULT_LOG.error("An exception occurred when external data was imported into Derby : {}", ex);
return RestResultUtils.failed(ex.getMessage());
}The snippet demonstrates that the try (DiskUtils.LineIterator iterator = DiskUtils.lineIterator(file)) construct automatically closes the file stream, eliminating the need for manual resource cleanup.
Recommended reading:
Why Redis Slows Down: A Complete Guide to Diagnosing Redis Performance Issues
Seven Diagrams Reveal the Essence of RocketMQ Storage Design
Second‑Round Interview at Tencent: Does Redis Transaction Support ACID?
Discussing Distributed Locks – Redis and Redisson Approaches
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
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.