Browse Source

Add documentation for streaming results.

Also us Github issue numbers on tests.

Original pull request #903
See #578, #971
pull/1002/head
Jens Schauder 5 years ago
parent
commit
377d841284
No known key found for this signature in database
GPG Key ID: 45CC872F17423DBF
  1. 2
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/QueryAnnotationHsqlIntegrationTests.java
  2. 33
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQueryUnitTests.java
  3. 14
      src/main/asciidoc/jdbc.adoc
  4. 9
      src/main/asciidoc/new-features.adoc

2
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/QueryAnnotationHsqlIntegrationTests.java

@ -174,7 +174,7 @@ public class QueryAnnotationHsqlIntegrationTests {
.containsExactlyInAnyOrder("a", "b"); .containsExactlyInAnyOrder("a", "b");
} }
@Test // DATAJDBC-356 @Test // GH-578
public void executeCustomQueryWithNamedParameterAndReturnTypeIsStream() { public void executeCustomQueryWithNamedParameterAndReturnTypeIsStream() {
repository.save(dummyEntity("a")); repository.save(dummyEntity("a"));

33
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.Repository;
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata; import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
import org.springframework.data.repository.core.support.PropertiesBasedNamedQueries; 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.ResultSetExtractor;
import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
@ -57,8 +56,7 @@ import org.springframework.util.ReflectionUtils;
* @author Mark Paluch * @author Mark Paluch
* @author Dennis Effing * @author Dennis Effing
*/ */
public class StringBasedJdbcQueryUnitTests { class StringBasedJdbcQueryUnitTests {
RowMapper<Object> defaultRowMapper; RowMapper<Object> defaultRowMapper;
NamedParameterJdbcOperations operations; NamedParameterJdbcOperations operations;
@ -66,7 +64,7 @@ public class StringBasedJdbcQueryUnitTests {
JdbcConverter converter; JdbcConverter converter;
@BeforeEach @BeforeEach
public void setup() throws NoSuchMethodException { void setup() throws NoSuchMethodException {
this.defaultRowMapper = mock(RowMapper.class); this.defaultRowMapper = mock(RowMapper.class);
this.operations = mock(NamedParameterJdbcOperations.class); this.operations = mock(NamedParameterJdbcOperations.class);
@ -75,17 +73,16 @@ public class StringBasedJdbcQueryUnitTests {
} }
@Test // DATAJDBC-165 @Test // DATAJDBC-165
public void emptyQueryThrowsException() { void emptyQueryThrowsException() {
JdbcQueryMethod queryMethod = createMethod("noAnnotation"); JdbcQueryMethod queryMethod = createMethod("noAnnotation");
Assertions.assertThatExceptionOfType(IllegalStateException.class) // Assertions.assertThatExceptionOfType(IllegalStateException.class) //
.isThrownBy(() -> createQuery(queryMethod) .isThrownBy(() -> createQuery(queryMethod).execute(new Object[] {}));
.execute(new Object[] {}));
} }
@Test // DATAJDBC-165 @Test // DATAJDBC-165
public void defaultRowMapperIsUsedByDefault() { void defaultRowMapperIsUsedByDefault() {
JdbcQueryMethod queryMethod = createMethod("findAll"); JdbcQueryMethod queryMethod = createMethod("findAll");
StringBasedJdbcQuery query = createQuery(queryMethod); StringBasedJdbcQuery query = createQuery(queryMethod);
@ -94,7 +91,7 @@ public class StringBasedJdbcQueryUnitTests {
} }
@Test // DATAJDBC-165, DATAJDBC-318 @Test // DATAJDBC-165, DATAJDBC-318
public void customRowMapperIsUsedWhenSpecified() { void customRowMapperIsUsedWhenSpecified() {
JdbcQueryMethod queryMethod = createMethod("findAllWithCustomRowMapper"); JdbcQueryMethod queryMethod = createMethod("findAllWithCustomRowMapper");
StringBasedJdbcQuery query = createQuery(queryMethod); StringBasedJdbcQuery query = createQuery(queryMethod);
@ -103,7 +100,7 @@ public class StringBasedJdbcQueryUnitTests {
} }
@Test // DATAJDBC-290 @Test // DATAJDBC-290
public void customResultSetExtractorIsUsedWhenSpecified() { void customResultSetExtractorIsUsedWhenSpecified() {
JdbcQueryMethod queryMethod = createMethod("findAllWithCustomResultSetExtractor"); JdbcQueryMethod queryMethod = createMethod("findAllWithCustomResultSetExtractor");
StringBasedJdbcQuery query = createQuery(queryMethod); StringBasedJdbcQuery query = createQuery(queryMethod);
@ -117,7 +114,7 @@ public class StringBasedJdbcQueryUnitTests {
} }
@Test // DATAJDBC-290 @Test // DATAJDBC-290
public void customResultSetExtractorAndRowMapperGetCombined() { void customResultSetExtractorAndRowMapperGetCombined() {
JdbcQueryMethod queryMethod = createMethod("findAllWithCustomRowMapperAndResultSetExtractor"); JdbcQueryMethod queryMethod = createMethod("findAllWithCustomRowMapperAndResultSetExtractor");
StringBasedJdbcQuery query = createQuery(queryMethod); StringBasedJdbcQuery query = createQuery(queryMethod);
@ -131,8 +128,9 @@ public class StringBasedJdbcQueryUnitTests {
"RowMapper is not expected to be custom"); "RowMapper is not expected to be custom");
} }
@Test // DATAJDBC-356 @Test // GH-578
public void streamQueryCallsQueryForStreamOnOperations() { void streamQueryCallsQueryForStreamOnOperations() {
JdbcQueryMethod queryMethod = createMethod("findAllWithStreamReturnType"); JdbcQueryMethod queryMethod = createMethod("findAllWithStreamReturnType");
StringBasedJdbcQuery query = createQuery(queryMethod); StringBasedJdbcQuery query = createQuery(queryMethod);
@ -141,20 +139,21 @@ public class StringBasedJdbcQueryUnitTests {
verify(operations).queryForStream(eq("some sql statement"), any(SqlParameterSource.class), any(RowMapper.class)); verify(operations).queryForStream(eq("some sql statement"), any(SqlParameterSource.class), any(RowMapper.class));
} }
@Test // DATAJDBC-356 @Test // GH-578
void streamQueryFallsBackToCollectionQueryWhenCustomResultSetExtractorIsSpecified() { void streamQueryFallsBackToCollectionQueryWhenCustomResultSetExtractorIsSpecified() {
JdbcQueryMethod queryMethod = createMethod("findAllWithStreamReturnTypeAndResultSetExtractor"); JdbcQueryMethod queryMethod = createMethod("findAllWithStreamReturnTypeAndResultSetExtractor");
StringBasedJdbcQuery query = createQuery(queryMethod); StringBasedJdbcQuery query = createQuery(queryMethod);
query.execute(new Object[] {}); query.execute(new Object[] {});
ArgumentCaptor<ResultSetExtractor> captor = ArgumentCaptor.forClass(ResultSetExtractor.class); ArgumentCaptor<ResultSetExtractor<?>> captor = ArgumentCaptor.forClass(ResultSetExtractor.class);
verify(operations).query(eq("some sql statement"), any(SqlParameterSource.class), captor.capture()); verify(operations).query(eq("some sql statement"), any(SqlParameterSource.class), captor.capture());
assertThat(captor.getValue()).isInstanceOf(CustomResultSetExtractor.class); assertThat(captor.getValue()).isInstanceOf(CustomResultSetExtractor.class);
} }
@Test // GH-774 @Test // GH-774
public void sliceQueryNotSupported() { void sliceQueryNotSupported() {
JdbcQueryMethod queryMethod = createMethod("sliceAll", Pageable.class); JdbcQueryMethod queryMethod = createMethod("sliceAll", Pageable.class);
@ -164,7 +163,7 @@ public class StringBasedJdbcQueryUnitTests {
} }
@Test // GH-774 @Test // GH-774
public void pageQueryNotSupported() { void pageQueryNotSupported() {
JdbcQueryMethod queryMethod = createMethod("pageAll", Pageable.class); JdbcQueryMethod queryMethod = createMethod("pageAll", Pageable.class);

14
src/main/asciidoc/jdbc.adoc

@ -466,6 +466,8 @@ interface PersonRepository extends PagingAndSortingRepository<Person, String> {
@Query("SELECT * FROM person WHERE lastname = :lastname") @Query("SELECT * FROM person WHERE lastname = :lastname")
List<Person> findByLastname(String lastname); <7> List<Person> findByLastname(String lastname); <7>
@Query("SELECT * FROM person WHERE lastname = :lastname")
Stream<Person> streamByLastname(String lastname); <8>
} }
---- ----
<1> The method shows a query for all people with the given `lastname`. <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. 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. <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. <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: 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`. 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]] [[jdbc.query-methods.at-query.custom-rowmapper]]
==== Custom `RowMapper` ==== Custom `RowMapper`

9
src/main/asciidoc/new-features.adoc

@ -3,8 +3,15 @@
This section covers the significant changes for each version. 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 <<jdbc.query-methods.at-query.streaming-results, streaming results>>.
* Support for specifying projection types as return type or using generics and providing a Class parameter to query methods.
[[new-features.2-2-0]] [[new-features.2-2-0]]
== `Page` and `Slice` support for <<jdbc.query-methods,derived queries>>. == What's New in Spring Data JDBC 2.2
* `Page` and `Slice` support for <<jdbc.query-methods,derived queries>>.
[[new-features.2-1-0]] [[new-features.2-1-0]]
== What's New in Spring Data JDBC 2.1 == What's New in Spring Data JDBC 2.1

Loading…
Cancel
Save