Do I risk a JDBC connection leak when streaming JOOQ results outside a try-with-resources block?
Asked Answered
J

1

9

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)

Jutland answered 22/2, 2016 at 16:8 Comment(0)
P
9

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

Philippe answered 22/2, 2016 at 17:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.