Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring Data … what? Spring Data’s mission is to provide a familiar and consistent, Spring-based programming model for data access while retaining the special traits of the underlying data store.
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Image Source: NASA.gov 375 Days 700+ Issues 16 Modules
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Image Source: NASA.gov 16 Modules 375 Days 700+ Issues Kotlin Performance Reactive
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Image Source: NASA.gov 16 Modules 375 Days 700+ Issues Kotlin Performance Reactive New Features Coroutines & Flow Declarative Reactive Transactions 60% faster finder methods* * for eg. JPA single attribute finder like 'findByTitle'
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Image Source: NASA.gov Reactive
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Image Source: NASA.gov Reactive Declarative Transactions
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Declarative Transactions @EnableTransactionManagement class Config extends AbstractReactiveMongoConfiguration { @Bean ReactiveTransactionManager mgr(ReactiveMongoDatabaseFactory f) { return new ReactiveMongoTransactionManager(dbFactory); } // ... } New in Moore
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Declarative Transactions @Transactional public Mono<Process> doSomething(Long id) { return findById(id) .flatMap(it -> start(template, it)) .flatMap(it -> verify(it)) .flatMap(it -> finish(template, it)); } template.inTransaction().execute(… .next() start(action,… finish(action,… New in Moore
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Image Source: NASA.gov Reactive Elasticsearch
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Why not…? public Mono<SearchResponse> search(SearchRequest request) { return Mono.create(sink -> client.searchAsync(request, options, new ActionListener<>() { @Override public void onResponse(SearchResponse searchResponse) { sink.success(searchResponse); } @Override public void onFailure(Exception e) { sink.error(e);
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Elasticsearch Client class Config extends AbstractReactiveElasticsearchConfiguration { @Bean @Override public ReactiveElasticsearchClient reactiveClient() { return ReactiveRestClients.create(localhost()); } } based on WebClient New in Moore
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Elasticsearch Template @Autowired ReactiveElasticsearchTemplate template; //... Criteria criteria = new Criteria("topics").contains("spring") .and("date").greaterThanEqual(today()) CriteriaQuery query = new CriteriaQuery(criteria); Flux<Conference> result = template.find(query, Conference.class); New in Moore
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Elasticsearch Repository interface ConferenceRepo extends ReactiveCrudRepository<…> { Flux<Conference> findAllByKeywordsContainsAndDateAfter(…); } @Autowired ConferenceRepo repo; //… Flux<Conference> result = repo.findAllByKeywordsContainsAndDateAfter("spring", today()); New in Moore
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Image Source: NASA.gov Reactive Querydsl
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Querydsl interface Repository extends …, QuerydslPredicateExecutor<Customer> QCustomer.customer.lastname.eq("Matthews")
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Querydsl interface Repository extends …, ReactiveQuerydslPredicateExecutor<…> @Autowired Repository repo; //… Predicate predicate = QCustomer.customer.lastname.eq("Matthews"); Flux<Customer> result = repo.findAll(predicate); New in Moore
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Kotlin val people = operations.query<Person>() .matching(query(where("lastname").isEqualTo("Matthews"))) .all() Kotlin Extension to avoid `is` (…
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Kotlin val people = operations.query<Person>() .matching(query(where("lastname").isEqualTo("Matthews"))) .all() List<Person> people = operations.query(Person.class) reified type parameter
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Kotlin type-safe query DSL val people = operations.query<Person>() .matching(query(Person::lastname isEqualTo "Matthews")) .all() where("lastname") .isEqualTo("Matthews") New in Moore New in Moore
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Kotlin operations.query<Person>() .matching(query(where("lastname").isEqualTo("Matthews"))) .doOnNext { … } .subscribe() New in Moore
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Coroutines val result = runBlocking { operations.query<Person>() .matching(query(where("lastname").isEqualTo("Matthews"))) .awaitSingle() } New in Moore
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Flow val result = runBlocking { operations.query<Person>() .matching(query(where("lastname").isEqualTo("Matthews"))) .asFlow().toList() } New in Moore
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Image Source: NASA.gov Performance
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ JMH Java Microbenchmark Harness baseline native code path Derived Query Annotated Query Transactional Query Spring Data
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ JMH @Benchmark public void findByTitle(Blackhole sink) { Query q = em.createQuery("select b from Book b where b.title = ?1"); q.setParameter(1, "title0"); sink.consume(query.getSingleResult()); } @Benchmark public void repositoryFindByTitle(Blackhole sink) { sink.consume(repository.findDerivedByTitle("title0")); } native code path Spring Data
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 33 Ops/sec* *spring-data-jpa in memory H2 SQL Mac Book Pro 3.2 GHz RC1 RC2 findAll 52.213 61.244 findByTitle 74.192 123.040 repositoryByTitle 70.344 120.333 repositoryByTitleDeclared 65.236 111.760
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 34 RC1 RC2 findAll 52.213 61.244 findByTitle 74.192 123.040 repositoryByTitle 70.344 120.333 repositoryByTitleDeclared 65.236 111.760 Ops/sec* *spring-data-jpa in memory H2 SQL Mac Book Pro 3.2 GHz
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 35 RC1 RC2 findAll 52.213 61.244 findByTitle 74.192 123.040 repositoryByTitle 70.344 120.333 repositoryByTitleDeclared 65.236 111.760 Ops/sec* *spring-data-jpa in memory H2 SQL Mac Book Pro 3.2 GHz Clean Room Scenario! Almost each and every performance benchmark avoids any kind of overhead whatsoever.
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Image Source: NASA.gov New Features
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Image Source: NASA.gov New Features Entity Callback API
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Modifying Entities via Events @Component class MongoListener extends AbstractMongoEventListener<Person> { @Override public void onBeforeSave(BeforeSaveEvent<Person> event) { event.getDocument().put(…) } } already converted (store specific) Person representation
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Modifying Entities via Callbacks @Bean BeforeSaveCallback<Person> beforeSave() { return (entity, document) -> { document.put(…); return entity; } } already converted (store specific) Person representation New in Moore
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Modifying Entities via Callbacks @Bean BeforeConvertCallback<Person> beforeConvert() { return (entity, collection) -> { return entity.withId(…); } } new Person object with and id set @Bean BeforeSaveCallback<Person> beforeSave() { return (entity, document) -> {…} } already converted (store specific) Person representation with changes applied New in Moore
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Modifying Entities via Callbacks @Bean ReactiveBeforeConvertCallback<Person> beforeConvert() { return (entity, collection) -> { return Mono.just(entity.withId(…)); } } New in Moore
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Image Source: NASA.gov New Features Declarative Aggregations
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Aggregation Framework API {$group:{_id:'$cust_id',total:{$sum:'$amount'}}} newAggregation(Order.class, group( Fields.from(Fields.field("_id", "cust_id"))) .sum("amount").as("total") );
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ MongoDB Aggregations {$group:{_id:'$cust_id',total:{$sum:'$amount'}}} newAggregation(Order.class, group( Fields.from(Fields.field("_id", "cust_id"))) .sum("amount").as("total") );
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ @Aggregation(" ") Declarative Aggregations {$group:{_id:'$cust_id',total:{$sum:'$amount'}}} New in Moore
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ interface OrderRepository extends CrudRepository<Order, Long> { @Aggregation(" ") List<TotalByCustomer> totalByCustomer(Sort sort); @Aggregation(pipeline={ "{$match:{customerId:?0}}", "{$count:total}"}) Long totalOrdersForCustomer(String customerId); } Declarative Aggregations {$group:{_id:'$cust_id',total:{$sum:'$amount'}}} { "total" : 101 } New in Moore
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Image Source: NASA.gov New Features Multiple out parameters JPA
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Multiple OUT Parameters @NamedStoredProcedureQuery(name = "User.s1p", procedureName = "s1p", parameters = { @StoredProcedureParameter(mode = IN, name = "in_1", type = …), @StoredProcedureParameter(mode = OUT, name = "out_1", type = …), @StoredProcedureParameter(mode = OUT, name = "out_2", type = …)}) @Table(name = "SD_User") class User { ... } interface UserRepository extends JpaRepository<…> { @Procedure(name = "User.s1p") Map<String, Integer> callS1P(@Param("in_1") Integer arg); @Procedure Map<String, Integer> s1p(@Param("in_1") Integer arg); New in Moore
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Image Source: NASA.gov New Features Redis Streams
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Redis Streams ID <millisecondsTime>-<sequenceNumber> Key/Value 1234-0 S-12 18°C r2d2 1234-1 S-13 9°C c3p0 1235-0 S-13 18.2°C bb8 XADD XRANGE XREAD New in Moore
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Redis Streams API @Autowired RedisTemplate template; StringRecord record = StreamRecords.string(…) .withStreamKey("my-stream"); template.streamOps().add(record); ID 1234-0 S-12 18°C 1234-1 S-13 9°C 1235-0 S-13 18.2°C template.streamOps().read(count(2), from(…)); XRANGE XADD New in Moore
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Redis Streams StreamReceiver rcvr; rcvr.receive(StreamOffset.fromStart("my-stream")) .doOnNext(msg -> { // … }) .subscribe(); ID 1234-0 S-12 18°C 1234-1 S-13 9°C 1235-0 S-13 18.2°C New in Moore
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Image Source: NASA.gov New Features …and more
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 57 …and more JDBC uses Spring HATEOAS 1.0 Read Only Properties insert/update methods SQL generation Embeddable load options Improved SSL support Dynamic port configuration
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 58 …and more ApacheTM Cassandra Id conversion Reactive GridFS JSON Schema generator Collation via annotation Fluent ChangeStream API Neo4j Spatial Types Exists projections Repository Range Queries Optimistic Locking Auditing support Derived delete Queries
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 59 …and more Non blocking connect Cluster Caching High Level Rest Client Alternative Mapper
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Image Source: NASA.gov …ready - set - go! spring-projects/ spring-data-examples
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Image Source: NASA.gov What’s next?
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Cassandra MongoDB JDBC Derived Queries Paging & Sorting Major Version Bumps shorter cycles Neo4j RX JDBC What’s next? SpringData R2DBC
Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Safe Harbor Statement The following is intended to outline the general direction of Pivotal's offerings. It is intended for information purposes only and may not be incorporated into any contract. Any information regarding pre-release of Pivotal offerings, future updates or other planned modifications is subject to ongoing evaluation by Pivotal and is subject to change. This information is provided without warranty or any kind, express or implied, and is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions regarding Pivotal's offerings. These purchasing decisions should only be based on features currently available. The development, release, and timing of any features or functionality described for Pivotal's offerings in this presentation remain at the sole discretion of Pivotal. Pivotal has no obligation to update forward looking information in this presentation.