I have a JOOQ query where I want to avoid materializing all Records at the same time. (However, I am fine with jointly materializing all bean objects created from them.)
I have the following simple method to load the data:
public List<CustomerInfo> getCustomers() {
return dslContext
.selectFrom(CUSTOMER)
// <-- note the missing .fetch()
.stream()
.map(CustomerInfo::new)
.collect(Collectors.toList());
}
Can this lead to a JDBC connection leak in any circumstances? (e.g. an Exception in CustomerInfo::new
)
A connection leak means some of the database request/transaction are not getting closed properly or are not getting committed and finally those connections are getting abondoned and closed permanently.
Use removeAbandoned, removeAbandonedTimeout and logAbandoned (if supported). This allows the pool to time the usage of a connection, and forcibly reclaim it.
I've tried my luck finding a way to register a reliable stream "completion" hook that fires on complete stream consumption or on any exception, but that's not possible, unfortunately: Register a Stream "completion" hook
So, indeed, the code you have shown is not correct. The correct way to operate with "lazy" streams (or Cursor
) is to use the try-with-resources statement. The following two are equivalent:
// Using a Stream
try (Stream<CustomerRecord> stream = dslContext.selectFrom(CUSTOMER).stream()) {
return stream.map(CustomerInfo::new).collect(Collectors.toList());
}
// Using a Cursor
try (Cursor<CustomerRecord> cursor = dslContext.selectFrom(CUSTOMER).fetchLazy()) {
return cursor.stream().map(CustomerInfo::new).collect(Collectors.toList());
}
Notice also the ResultQuery.stream()
javadoc:
This is essentially the same as fetchLazy() but instead of returning a Cursor, a Java 8 Stream is returned. Clients should ensure the Stream is properly closed, e.g. in a try-with-resources statement
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With