diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/QueryAnnotationHsqlIntegrationTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/QueryAnnotationHsqlIntegrationTests.java index 28aac1286..824902984 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/QueryAnnotationHsqlIntegrationTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/QueryAnnotationHsqlIntegrationTests.java @@ -174,7 +174,7 @@ public class QueryAnnotationHsqlIntegrationTests { .containsExactlyInAnyOrder("a", "b"); } - @Test // DATAJDBC-356 + @Test // GH-578 public void executeCustomQueryWithNamedParameterAndReturnTypeIsStream() { repository.save(dummyEntity("a")); diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQueryUnitTests.java b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQueryUnitTests.java index d5704c13f..6e3a5d96b 100644 --- a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQueryUnitTests.java +++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQueryUnitTests.java @@ -40,7 +40,6 @@ import org.springframework.data.relational.core.mapping.RelationalMappingContext import org.springframework.data.repository.Repository; import org.springframework.data.repository.core.support.DefaultRepositoryMetadata; import org.springframework.data.repository.core.support.PropertiesBasedNamedQueries; -import org.springframework.data.repository.query.DefaultParameters; import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; @@ -57,8 +56,7 @@ import org.springframework.util.ReflectionUtils; * @author Mark Paluch * @author Dennis Effing */ -public class StringBasedJdbcQueryUnitTests { - +class StringBasedJdbcQueryUnitTests { RowMapper defaultRowMapper; NamedParameterJdbcOperations operations; @@ -66,7 +64,7 @@ public class StringBasedJdbcQueryUnitTests { JdbcConverter converter; @BeforeEach - public void setup() throws NoSuchMethodException { + void setup() throws NoSuchMethodException { this.defaultRowMapper = mock(RowMapper.class); this.operations = mock(NamedParameterJdbcOperations.class); @@ -75,17 +73,16 @@ public class StringBasedJdbcQueryUnitTests { } @Test // DATAJDBC-165 - public void emptyQueryThrowsException() { + void emptyQueryThrowsException() { JdbcQueryMethod queryMethod = createMethod("noAnnotation"); Assertions.assertThatExceptionOfType(IllegalStateException.class) // - .isThrownBy(() -> createQuery(queryMethod) - .execute(new Object[] {})); + .isThrownBy(() -> createQuery(queryMethod).execute(new Object[] {})); } @Test // DATAJDBC-165 - public void defaultRowMapperIsUsedByDefault() { + void defaultRowMapperIsUsedByDefault() { JdbcQueryMethod queryMethod = createMethod("findAll"); StringBasedJdbcQuery query = createQuery(queryMethod); @@ -94,7 +91,7 @@ public class StringBasedJdbcQueryUnitTests { } @Test // DATAJDBC-165, DATAJDBC-318 - public void customRowMapperIsUsedWhenSpecified() { + void customRowMapperIsUsedWhenSpecified() { JdbcQueryMethod queryMethod = createMethod("findAllWithCustomRowMapper"); StringBasedJdbcQuery query = createQuery(queryMethod); @@ -103,7 +100,7 @@ public class StringBasedJdbcQueryUnitTests { } @Test // DATAJDBC-290 - public void customResultSetExtractorIsUsedWhenSpecified() { + void customResultSetExtractorIsUsedWhenSpecified() { JdbcQueryMethod queryMethod = createMethod("findAllWithCustomResultSetExtractor"); StringBasedJdbcQuery query = createQuery(queryMethod); @@ -117,7 +114,7 @@ public class StringBasedJdbcQueryUnitTests { } @Test // DATAJDBC-290 - public void customResultSetExtractorAndRowMapperGetCombined() { + void customResultSetExtractorAndRowMapperGetCombined() { JdbcQueryMethod queryMethod = createMethod("findAllWithCustomRowMapperAndResultSetExtractor"); StringBasedJdbcQuery query = createQuery(queryMethod); @@ -131,8 +128,9 @@ public class StringBasedJdbcQueryUnitTests { "RowMapper is not expected to be custom"); } - @Test // DATAJDBC-356 - public void streamQueryCallsQueryForStreamOnOperations() { + @Test // GH-578 + void streamQueryCallsQueryForStreamOnOperations() { + JdbcQueryMethod queryMethod = createMethod("findAllWithStreamReturnType"); StringBasedJdbcQuery query = createQuery(queryMethod); @@ -141,20 +139,21 @@ public class StringBasedJdbcQueryUnitTests { verify(operations).queryForStream(eq("some sql statement"), any(SqlParameterSource.class), any(RowMapper.class)); } - @Test // DATAJDBC-356 + @Test // GH-578 void streamQueryFallsBackToCollectionQueryWhenCustomResultSetExtractorIsSpecified() { + JdbcQueryMethod queryMethod = createMethod("findAllWithStreamReturnTypeAndResultSetExtractor"); StringBasedJdbcQuery query = createQuery(queryMethod); query.execute(new Object[] {}); - ArgumentCaptor captor = ArgumentCaptor.forClass(ResultSetExtractor.class); + ArgumentCaptor> captor = ArgumentCaptor.forClass(ResultSetExtractor.class); verify(operations).query(eq("some sql statement"), any(SqlParameterSource.class), captor.capture()); assertThat(captor.getValue()).isInstanceOf(CustomResultSetExtractor.class); } @Test // GH-774 - public void sliceQueryNotSupported() { + void sliceQueryNotSupported() { JdbcQueryMethod queryMethod = createMethod("sliceAll", Pageable.class); @@ -164,7 +163,7 @@ public class StringBasedJdbcQueryUnitTests { } @Test // GH-774 - public void pageQueryNotSupported() { + void pageQueryNotSupported() { JdbcQueryMethod queryMethod = createMethod("pageAll", Pageable.class); diff --git a/src/main/asciidoc/jdbc.adoc b/src/main/asciidoc/jdbc.adoc index ce7d4c253..e43054221 100644 --- a/src/main/asciidoc/jdbc.adoc +++ b/src/main/asciidoc/jdbc.adoc @@ -466,6 +466,8 @@ interface PersonRepository extends PagingAndSortingRepository { @Query("SELECT * FROM person WHERE lastname = :lastname") List findByLastname(String lastname); <7> + @Query("SELECT * FROM person WHERE lastname = :lastname") + Stream streamByLastname(String lastname); <8> } ---- <1> The method shows a query for all people with the given `lastname`. @@ -478,6 +480,7 @@ Thus, the method name results in a query expression of `SELECT … FROM person W It completes with `IncorrectResultSizeDataAccessException` on non-unique results. <6> In contrast to <3>, the first entity is always emitted even if the query yields more result documents. <7> The `findByLastname` method shows a query for all people with the given last name. +<8> The `streamByLastname` method returns a `Stream` which makes values possible as soon as they are returned from the database. ==== The following table shows the keywords that are supported for query methods: @@ -622,6 +625,17 @@ Named queries are expected to be provided in the property file `META-INF/jdbc-na The location of that file may be changed by setting a value to `@EnableJdbcRepositories.namedQueriesLocation`. +[[jdbc.query-methods.at-query.streaming-results]] +==== Streaming Results + +When you specify `Stream` as the return type of a query method Spring Data JDBC will return elements as soon as they become available. +When dealing with large amounts of data this is suitable for reducing latency and memory requirements. + +The stream contains an open connection to the database. +To avoid memory leaks that connection needs to be closed eventually by closing the stream. +The recommended way to do that is a try-with-resource clause. +It also means once the connection to the database is closed, the stream cannot obtain further elements and will likely throw an exception. + [[jdbc.query-methods.at-query.custom-rowmapper]] ==== Custom `RowMapper` diff --git a/src/main/asciidoc/new-features.adoc b/src/main/asciidoc/new-features.adoc index 293d155c4..fb4d73d69 100644 --- a/src/main/asciidoc/new-features.adoc +++ b/src/main/asciidoc/new-features.adoc @@ -3,8 +3,15 @@ This section covers the significant changes for each version. +[[new-features.2-3-0]] +== What's New in Spring Data JDBC 2.3 + +* Support for <>. +* Support for specifying projection types as return type or using generics and providing a Class parameter to query methods. + [[new-features.2-2-0]] -== `Page` and `Slice` support for <>. +== What's New in Spring Data JDBC 2.2 +* `Page` and `Slice` support for <>. [[new-features.2-1-0]] == What's New in Spring Data JDBC 2.1