### Create a Basic Query By Example Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/query-by-example.adoc Create a domain object with the criteria, then use it to create an `Example`. Execute the query through the repository. Use `findOne` for a single item. ```java var probe = new Employee("Frodo", null, null); var example = Example.of(probe); var employee = repository.findOne(example); assertThat(employee).hasValueSatisfying(e -> { assertThat(e.getName()).isEqualTo("Frodo"); }); ``` -------------------------------- ### Customizing Query By Example with ExampleMatcher Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/query-by-example.adoc Create a custom `ExampleMatcher` to control matching behavior. This example matches on all fields, uses a wildcard for the 'name' field, matches against null, and ignores the 'role' field. ```java var probe = new Employee("Frodo", null, null); var example = Example.of(probe, ExampleMatcher.matching() .withStringMatcher(StringMatcher.ENDING) .withIncludeNullValues() .withIgnoredPaths("role")); var employee = repository.findOne(example); assertThat(employee).hasValueSatisfying(e -> { assertThat(e.getName()).isEqualTo("Frodo"); }); ``` -------------------------------- ### Example R2DBC Application Output Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/getting-started.adoc Sample log output from a running R2DBC application, showing SQL execution and retrieved data. ```text 2018-11-28 10:47:03,893 DEBUG ework.core.DatabaseClient: 310 - Executing SQL statement [CREATE TABLE person( id VARCHAR(255) PRIMARY KEY, name VARCHAR(255), age INT )] 2018-11-28 10:47:04,074 DEBUG ework.core.DatabaseClient: 908 - Executing SQL statement [INSERT INTO person (id, name, age) VALUES($1, $2, $3)] 2018-11-28 10:47:04,092 DEBUG ework.core.DatabaseClient: 575 - Executing SQL statement [SELECT id, name, age FROM person] 2018-11-28 10:47:04,436 INFO org.spring.r2dbc.example.R2dbcApp: 43 - Person [id='joe', name='Joe', age=34] ``` -------------------------------- ### Custom R2dbcEntityTemplate with MySQL Dialect Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/repositories.adoc Example of creating a custom R2dbcEntityTemplate instance specifying the MySQL dialect. ```java return new R2dbcEntityTemplate(databaseClient, MySqlDialect.INSTANCE); } } ``` -------------------------------- ### Example Repository Interface Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/jdbc/aot.adoc This is an example of a Spring Data JDBC repository interface that would be processed during AOT compilation. ```java interface UserRepository extends CrudRepository { ``` -------------------------------- ### Java Configuration for Spring Data JDBC Repositories Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/jdbc/getting-started.adoc Activate Spring Data JDBC repositories using Java configuration. This example sets up a DataSource, NamedParameterJdbcOperations, and a TransactionManager. ```java @Configuration @EnableJdbcRepositories // <1> class ApplicationConfig extends AbstractJdbcConfiguration { // <2> @Bean DataSource dataSource() { // <3> EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder(); return builder.setType(EmbeddedDatabaseType.HSQL).build(); } @Bean NamedParameterJdbcOperations namedParameterJdbcOperations(DataSource dataSource) { // <4> return new NamedParameterJdbcTemplate(dataSource); } @Bean TransactionManager transactionManager(DataSource dataSource) { // <5> return new DataSourceTransactionManager(dataSource); } } ``` -------------------------------- ### Execute Integration Tests with Specific Database Source: https://github.com/spring-projects/spring-data-relational/blob/main/spring-data-jdbc/README.adoc Run integration tests against a specific database by activating Spring profiles. Requires a local Docker installation. ```bash mvn verify -Dspring.profiles.active= ``` -------------------------------- ### Paging Access to Person Entities Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/repositories.adoc Example demonstrating how to retrieve all Person objects using a repository. It utilizes Spring's unit test support and StepVerifier for verification. ```java include::example$r2dbc/PersonRepositoryTests.java[tags=class] ``` -------------------------------- ### Optimistic Locking Example Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/entity-persistence.adoc Demonstrates optimistic locking with R2DBC entity template. Inserts a person, loads it, updates it, and then attempts to update the old version, which fails. ```java @Table class Person { @Id Long id; String firstname; String lastname; @Version Long version; } R2dbcEntityTemplate template = …; Mono daenerys = template.insert(new Person("Daenerys")); <1> Person other = template.select(Person.class) .matching(query(where("id").is(daenerys.getId()))) .first().block(); <2> daenerys.setLastname("Targaryen"); template.update(daenerys); <3> template.update(other).subscribe(); // emits OptimisticLockingFailureException <4> ``` -------------------------------- ### Configure R2DBC Mapping Support with Java Configuration Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/mapping.adoc Example of a Spring Java configuration class for R2DBC mapping. It requires implementing a ConnectionFactory and optionally allows adding custom converters. ```java @Configuration public class MyAppConfig extends AbstractR2dbcConfiguration { public ConnectionFactory connectionFactory() { return ConnectionFactories.get("r2dbc:…"); } // the following are optional @Override protected List getCustomConverters() { return List.of(new PersonReadConverter(), new PersonWriteConverter()); } } ``` -------------------------------- ### Person Load Event Listener Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/jdbc/events.adoc Implement a listener for specific domain types by extending AbstractRelationalEventListener. This example logs Person entities after they are loaded. ```java class PersonLoadListener extends AbstractRelationalEventListener { @Override protected void onAfterLoad(AfterLoadEvent personLoad) { LOG.info(personLoad.getEntity()); } } ``` -------------------------------- ### AOT Repository Metadata (JSON) Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/jdbc/aot.adoc Example of AOT generated metadata for a JDBC repository, detailing methods, signatures, and query information. ```json { "name": "com.acme.UserRepository", "module": "JDBC", "type": "IMPERATIVE", "methods": [ { "name": "findUserNoArgumentsBy", "signature": "public abstract java.util.List com.acme.UserRepository.findUserNoArgumentsBy()", "query": { "query": "SELECT * FROM User" } }, { "name": "findPageOfUsersByLastnameStartingWith", "signature": "public abstract org.springframework.data.domain.Page com.acme.UserRepository.findPageOfUsersByLastnameStartingWith(java.lang.String,org.springframework.data.domain.Pageable)", "query": { "query": "SELECT * FROM User u WHERE lastname LIKE :lastname", "count-query": "SELECT COUNT(*) FROM User WHERE lastname LIKE :lastname" } }, { "name": "findAnnotatedQueryByEmailAddress", "signature": "public abstract com.acme.User com.acme.UserRepository.findAnnotatedQueryByEmailAddress(java.lang.String)", "query": { "query": "select * from User where emailAddress = ?1" } }, { "name": "findByEmailAddress", "signature": "public abstract com.acme.User com.acme.UserRepository.findByEmailAddress(java.lang.String)", "query": { "name": "User.findByEmailAddress", "query": "SELECT * FROM User WHERE emailAddress = ?1" } }, { "name": "count", "signature": "public abstract long org.springframework.data.repository.CrudRepository.count()", "fragment": { "fragment": "org.springframework.data.jdbc.repository.support.SimpleJdbcRepository" } } ] } ``` -------------------------------- ### Spring Data R2DBC: Service Layer Example Source: https://github.com/spring-projects/spring-data-relational/blob/main/README.adoc Illustrates a service class `MyService` using `PersonRepository` for reactive database operations, returning `Flux` and `Mono` for asynchronous data streams. ```java @Service class MyService { private final PersonRepository repository; public MyService(PersonRepository repository) { this.repository = repository; } public Flux doWork() { Person person = new Person(); person.setFirstname("Jens"); person.setLastname("Schauder"); repository.save(person); Mono deleteAll = repository.deleteAll(); Flux lastNameResults = repository.findByLastname("Schauder"); Flux firstNameResults = repository.findByFirstnameLike("Je%"); ``` -------------------------------- ### Spring Data JDBC: Service Layer Example Source: https://github.com/spring-projects/spring-data-relational/blob/main/README.adoc Demonstrates a service class `MyService` that utilizes `PersonRepository` to perform database operations like saving, deleting, and querying `Person` entities. ```java @Service class MyService { private final PersonRepository repository; public MyService(PersonRepository repository) { this.repository = repository; } public void doWork() { repository.deleteAll(); Person person = new Person(); person.setFirstname("Jens"); person.setLastname("Schauder"); repository.save(person); List lastNameResults = repository.findByLastname("Schauder"); List firstNameResults = repository.findByFirstnameLike("Je%"); } } ``` -------------------------------- ### Derived Query with Pagination Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/jdbc/aot.adoc This method shows a derived query that utilizes pagination. It finds users whose last names start with a given string and returns a page of results. ```APIDOC ## findPageOfUsersByLastnameStartingWith ### Description Derived query using pagination. Finds users whose last names start with the provided string. ### Method GET (or appropriate HTTP method if this were an HTTP API) ### Endpoint /users ### Parameters #### Query Parameters - **lastname** (string) - Required - The starting string for the last name search. - **page** (Pageable) - Required - Pagination information (page number, size, sort). ### Response #### Success Response (200) - **Page** - A page object containing a list of User objects and pagination metadata. ### Response Example ```json { "content": [ { "id": 1, "username": "john_doe", "emailAddress": "john.doe@example.com" } ], "pageable": { "sort": {"empty": false, "sorted": true, "unsorted": false}, "offset": 0, "pageNumber": 0, "pageSize": 20, "paged": true, "unpaged": false }, "last": true, "totalPages": 1, "totalElements": 1, "first": true, "size": 20, "number": 0, "sort": {"empty": false, "sorted": true, "unsorted": false}, "numberOfElements": 1, "empty": false } ``` ``` -------------------------------- ### Person to OutboundRow Writing Converter Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/mapping.adoc Example of a Spring Data R2DBC writing converter that transforms a Person object into an OutboundRow for database insertion. ```java @WritingConverter public class PersonWriteConverter implements Converter { public OutboundRow convert(Person source) { OutboundRow row = new OutboundRow(); row.put("id", Parameter.from(source.getId())); row.put("name", Parameter.from(source.getFirstName())); row.put("age", Parameter.from(source.getAge())); return row; } } ``` -------------------------------- ### Register Custom RowMappers with QueryMappingConfiguration Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/jdbc/query-methods.adoc This example shows how to configure custom RowMappers for specific entity types using DefaultQueryMappingConfiguration. This is useful when you want to apply a specific RowMapper to all methods returning a certain type. ```java @Bean QueryMappingConfiguration rowMappers() { return new DefaultQueryMappingConfiguration() .register(Person.class, new PersonRowMapper()) .register(Address.class, new AddressRowMapper()); } ``` -------------------------------- ### Example Domain Object for R2DBC Mapping Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/mapping.adoc Demonstrates a simple domain object annotated for R2DBC mapping. Use @Table to allow the classpath scanner to find and pre-process domain objects for metadata extraction. The @Id annotation specifies the primary key property. ```java package com.mycompany.domain; @Table public class Person { @Id private Long id; private Integer ssn; private String firstName; private String lastName; } ``` -------------------------------- ### Implement Reading Converter for String to Boolean Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/jdbc/mapping.adoc Provides an example of a Spring converter to read 'T' or 'F' strings from the database and convert them to Boolean values. Annotate with @ReadingConverter to specify the direction. ```java @ReadingConverter public class StringToBooleanConverter implements Converter { @Override public Boolean convert(String source) { return source != null && source.equalsIgnoreCase("T") ? Boolean.TRUE : Boolean.FALSE; } } ``` -------------------------------- ### Build Documentation with Maven Source: https://github.com/spring-projects/spring-data-relational/blob/main/README.adoc Builds the project documentation using Maven. This command also builds the project but skips running tests. ```bash $ ./mvnw clean install -Pantora ``` -------------------------------- ### Build Spring Data with Maven Wrapper Source: https://github.com/spring-projects/spring-data-relational/blob/main/README.adoc Execute this command to build the project using the Maven wrapper. JDK 17 is required. ```bash $ ./mvnw clean install ``` -------------------------------- ### Run Integration Tests (All Databases, Ignore Missing Licenses) Source: https://github.com/spring-projects/spring-data-relational/blob/main/README.adoc Runs integration tests against all supported databases while ignoring tests that require explicit license acceptance by using the 'ignore-missing-license' profile. ```bash ./mvnw clean install -Pall-dbs,ignore-missing-license ``` -------------------------------- ### Run Integration Tests (All Supported Databases) Source: https://github.com/spring-projects/spring-data-relational/blob/main/README.adoc Activates the 'all-dbs' Maven profile to run integration tests against all supported databases. Requires a 'container-license-acceptance.txt' on the classpath. ```bash ./mvnw clean install -Pall-dbs ``` -------------------------------- ### Execute Unit and Integration Tests (In-Memory) Source: https://github.com/spring-projects/spring-data-relational/blob/main/spring-data-jdbc/README.adoc Run fast-running unit and integration tests using an in-memory database with Maven. ```bash mvn test ``` -------------------------------- ### PersonRepository with Query Methods Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/jdbc/query-methods.adoc Demonstrates various query methods for a Person repository, including simple property-based queries, queries with sorting and pagination, single entity retrieval, and custom queries using @Query. ```java interface PersonRepository extends PagingAndSortingRepository { List findByFirstname(String firstname); List findByFirstnameOrderByLastname(String firstname, Pageable pageable); Slice findByLastname(String lastname, Pageable pageable); Page findByLastname(String lastname, Pageable pageable); Person findByFirstnameAndLastname(String firstname, String lastname); Person findFirstByLastname(String lastname); @Query("SELECT * FROM person WHERE lastname = :lastname") List findByLastname(String lastname); @Query("SELECT * FROM person WHERE lastname = :lastname") Stream streamByLastname(String lastname); @Query("SELECT * FROM person WHERE username = :#{ principal?.username }") Person findActiveUser(); } ``` -------------------------------- ### Select Entities Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/entity-persistence.adoc Shows how to select entities using R2dbcEntityTemplate with a Query object to define criteria, projections, and ordering. Supports database-agnostic pagination. ```java r2dbcEntityTemplate.select(Person.class).all().subscribe(System.out::println); ``` -------------------------------- ### Run Tests with All Supported Databases Source: https://github.com/spring-projects/spring-data-relational/blob/main/spring-data-jdbc/README.adoc Execute unit tests and all integration tests against all supported databases using the 'all-dbs' Maven profile. ```bash mvn test -Pall-dbs ``` -------------------------------- ### ReactivePersonRepository with Query Methods Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/query-methods.adoc Demonstrates various query methods that can be declared in a reactive repository interface, including simple property-based queries, queries with publishers, ordering, and custom annotated queries. ```java interface ReactivePersonRepository extends ReactiveSortingRepository { Flux findByFirstname(String firstname); Flux findByFirstname(Publisher firstname); Flux findByFirstnameOrderByLastname(String firstname, Pageable pageable); Mono findByFirstnameAndLastname(String firstname, String lastname); Mono findFirstByLastname(String lastname); @Query("SELECT * FROM person WHERE lastname = :lastname") Flux findByLastname(String lastname); @Query("SELECT firstname, lastname FROM person WHERE lastname = $1") Mono findFirstByLastname(String lastname); } ``` -------------------------------- ### Update Name using Modifying Query Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/jdbc/query-methods.adoc Example of a modifying query to update the 'name' field in the DUMMYENTITY table. Use this for direct database updates where events or callbacks are not needed. ```java @Modifying @Query("UPDATE DUMMYENTITY SET name = :name WHERE id = :id") boolean updateName(@Param("id") Long id, @Param("name") String name); ``` -------------------------------- ### Simple Select Query Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/entity-persistence.adoc Illustrates a basic select query using R2dbcEntityTemplate to fetch all rows of a specific domain type. Results are returned as a Flux. ```java r2dbcEntityTemplate.select(Person.class).all(); ``` -------------------------------- ### Fetch All SWCharacter Objects in Kotlin Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/kotlin.adoc Concise Kotlin syntax for fetching all SWCharacter objects, utilizing type inference. Both provided syntaxes are equivalent. ```kotlin val characters = client.select().from().fetch().all() // or (both are equivalent) val characters : Flux = client.select().from().fetch().all() ``` -------------------------------- ### Create Person Table Schema Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/getting-started.adoc SQL statement to create the 'person' table with id, name, and age columns in the database. ```sql CREATE TABLE person( id VARCHAR(255) PRIMARY KEY, name VARCHAR(255), age INT ); ``` -------------------------------- ### Enum Mapping with Custom Converters Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/mapping.adoc Demonstrates how to configure custom converters for enum types to ensure native database enum value mapping instead of string conversion. ```java enum Color { Grey, Blue } class ColorConverter extends EnumWriteSupport { } class Product { @Id long id; Color color; // … } ``` -------------------------------- ### Sample Person Entity Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/repositories.adoc A sample Person entity class with an ID, firstname, and lastname. Used to demonstrate repository usage. ```java public class Person { @Id private Long id; private String firstname; private String lastname; // … getters and setters omitted } ``` -------------------------------- ### Select for Next Sequence Value in PostgreSQL Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/partials/sequences.adoc When persisting an entity with a sequence-annotated ID, Spring Data executes a `SELECT` statement to retrieve the next value from the specified sequence before the insert operation. This example shows the query for PostgreSQL. ```sql SELECT nextval('public.my_seq'); ``` -------------------------------- ### Fetch All SWCharacter Objects in Java Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/kotlin.adoc Standard Java approach to fetch all SWCharacter objects using DatabaseClient. ```java Flux characters = client.select().from(SWCharacter.class).fetch().all(); ``` -------------------------------- ### Spring Converter for R2DBC Row to Person POJO Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/mapping.adoc An example implementation of a Spring Converter for reading R2DBC data. This converter transforms a Row object into a Person POJO, extracting 'id', 'name', and 'age' fields. It is annotated with @ReadingConverter to indicate its purpose. ```java @ReadingConverter public class PersonReadConverter implements Converter { public Person convert(Row source) { Person p = new Person(source.get("id", String.class),source.get("name", String.class)); p.setAge(source.get("age", Integer.class)); return p; } } ``` -------------------------------- ### Complex Select Query with WHERE and ORDER BY Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/entity-persistence.adoc Demonstrates constructing a more complex query with R2dbcEntityTemplate, specifying the table name, WHERE conditions, and ORDER BY clauses. Supports fetching a single result. ```java r2dbcEntityTemplate.select(query(where("firstname").like("Test%") .and("lastname").like("Test%")) .orderBy(Sort.by("firstname")) .as(Person.class)) .first(); ``` -------------------------------- ### Derived Delete Queries with Different Return Types Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/query-methods.adoc Demonstrates derived delete queries using `deleteBy` and `delete...By` with varying return types to indicate the outcome of the deletion operation. ```java interface ReactivePersonRepository extends ReactiveSortingRepository { Mono deleteByLastname(String lastname); Mono deletePersonByLastname(String lastname); Mono deletePersonByLastname(String lastname); } ``` -------------------------------- ### Activate Auditing with Java Configuration Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/jdbc/auditing.adoc Add `@EnableJdbcAuditing` to your configuration class to enable auditing. Provide an `AuditorAware` bean to specify the current user. ```java @Configuration @EnableJdbcAuditing class Config { @Bean AuditorAware auditorProvider() { return new AuditorAwareImpl(); } } ``` -------------------------------- ### Register ConnectionFactory with Java Configuration Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/getting-started.adoc Register an instance of io.r2dbc.spi.ConnectionFactory using Java-based bean metadata. This approach also provides an ExceptionTranslator and registers DatabaseClient. ```java @Configuration public class ApplicationConfiguration extends AbstractR2dbcConfiguration { @Override @Bean public ConnectionFactory connectionFactory() { return … } } ``` -------------------------------- ### Insert and Select Entities Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/entity-persistence.adoc Demonstrates how to insert a row and retrieve its contents using R2dbcEntityTemplate. Ensure the Id property is numeric for auto-generation. ```java Person person = new Person(null, "Test", "Test"); r2dbcEntityTemplate.insert(person).flatMap(inserted -> { return r2dbcEntityTemplate.selectOne(query(where("id").is(inserted.getId())), Person.class); }).subscribe(System.out::println); ``` -------------------------------- ### Configure MyBatisJdbcConfiguration Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/jdbc/mybatis.adoc Import MyBatisJdbcConfiguration into your application configuration to enable MyBatis integration. Ensure a SqlSessionFactoryBean is defined. ```java import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories; import org.mybatis.spring.SqlSessionFactoryBean; @Configuration @EnableJdbcRepositories @Import(MyBatisJdbcConfiguration.class) class Application { @Bean SqlSessionFactoryBean sqlSessionFactoryBean() { // Configure MyBatis here } } ``` -------------------------------- ### Java Configuration for R2DBC Repositories Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/repositories.adoc Java configuration class to enable R2DBC repositories using @EnableR2dbcRepositories. Scans the annotated configuration class's package for repositories if no base package is configured. ```java @Configuration @EnableR2dbcRepositories class ApplicationConfig extends AbstractR2dbcConfiguration { @Override public ConnectionFactory connectionFactory() { return … } } ``` -------------------------------- ### Basic Repository Interface for Person Entities Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/repositories.adoc A basic repository interface extending ReactiveCrudRepository for persisting Person entities. Custom query methods can be added. ```java public interface PersonRepository extends ReactiveCrudRepository { // additional custom query methods go here } ``` -------------------------------- ### Enable R2DBC Auditing with JavaConfig Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/auditing.adoc Annotate your configuration class with @EnableR2dbcAuditing to activate auditing. Optionally, provide a custom ReactiveAuditorAware bean to specify the current user. ```java @Configuration @EnableR2dbcAuditing class Config { @Bean public ReactiveAuditorAware myAuditorProvider() { return new AuditorAwareImpl(); } } ``` -------------------------------- ### User Repository Interface Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/jdbc/aot.adoc Defines various methods for querying User entities, including derived queries, annotated queries, and named queries. ```java List findUserNoArgumentsBy(); Page findPageOfUsersByLastnameStartingWith(String lastname, Pageable page); @Query("select * from User u where username = ?1") User findAnnotatedQueryByEmailAddress(String username); User findByEmailAddress(String emailAddress); } ``` -------------------------------- ### MySQL Configuration for Multiple Databases Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/repositories.adoc Configuration for using multiple R2DBC databases, specifically MySQL. It defines a ConnectionFactory and R2dbcEntityOperations bean for the MySQL database. ```java @Configuration @EnableR2dbcRepositories(basePackages = "com.acme.mysql", entityOperationsRef = "mysqlR2dbcEntityOperations") static class MySQLConfiguration { @Bean @Qualifier("mysql") public ConnectionFactory mysqlConnectionFactory() { return … } @Bean public R2dbcEntityOperations mysqlR2dbcEntityOperations(@Qualifier("mysql") ConnectionFactory connectionFactory) { DatabaseClient databaseClient = DatabaseClient.create(connectionFactory); ``` -------------------------------- ### SpEL Expression for Dynamic Table Names Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/query-methods.adoc Shows how to use SpEL expressions to dynamically determine table names within a query. This is useful when table names can change or are determined at runtime. ```java interface PersonRepository { @Query("SELECT * FROM #{#tableName}") Flux findAllByTableName(); } ``` -------------------------------- ### Using @Embedded.Nullable Shortcut Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/partials/mapping.adoc Demonstrates the use of the @Embedded.Nullable shortcut for @Embedded(onEmpty = USE_NULL) to reduce verbosity. This shortcut also sets JSR-305 @javax.annotation.Nonnull accordingly. ```java class MyEntity { @Id Integer id; @Embedded.Nullable <1> EmbeddedEntity embeddedEntity; } ``` -------------------------------- ### Derived Query without Arguments Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/jdbc/aot.adoc This method demonstrates a derived query that does not require any arguments. It selects all records from the User table. ```APIDOC ## findUserNoArgumentsBy ### Description Derived query without arguments. Selects all users. ### Method GET (or appropriate HTTP method if this were an HTTP API) ### Endpoint /users ### Response #### Success Response (200) - **List** - A list of User objects. ### Response Example ```json [ { "id": 1, "username": "john_doe", "emailAddress": "john.doe@example.com" } ] ``` ``` -------------------------------- ### Enable JDBC Logging Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/jdbc/getting-started.adoc Configure application properties to set the logging level for Spring JDBC to DEBUG, enabling detailed SQL statement logging. ```properties logging.level.org.springframework.jdbc=DEBUG ``` -------------------------------- ### SpEL Expression for Predicate Values Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/query-methods.adoc Demonstrates using SpEL expressions within a query to dynamically provide predicate values. This allows for runtime evaluation of query conditions based on method arguments. ```java interface PersonRepository { @Query("SELECT * FROM person WHERE lastname = #{[0]}") Flux findByLastname(String lastname); } ``` -------------------------------- ### Implement Writing Converter for Boolean to String Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/jdbc/mapping.adoc Shows how to implement a Spring converter to write Boolean values as 'T' or 'F' strings to the database. Annotate with @WritingConverter to specify the direction of conversion. ```java import org.springframework.core.convert.converter.Converter; @WritingConverter public class BooleanToStringConverter implements Converter { @Override public String convert(Boolean source) { return source != null && source ? "T" : "F"; } } ``` -------------------------------- ### Logging Before Save Event Listener Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/jdbc/events.adoc Register an ApplicationListener bean to log entities before they are saved. This listener is generic and handles Object types. ```java @Bean ApplicationListener> loggingSaves() { return event -> { Object entity = event.getEntity(); LOG.info("{} is getting saved.", entity); }; } ``` -------------------------------- ### Custom Query Declaration with @Query Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/query-methods.adoc Illustrates how to declare a custom query method using the `@Query` annotation with a specific SQL statement. This allows for complex queries not achievable through derived methods. ```java interface UserRepository extends ReactiveCrudRepository { @Query("SELECT first_name, last_name FROM user WHERE email_address = :email") Flux findByEmailAddress(@Param("email") String email); } ``` -------------------------------- ### Facade for Defining Transactions Across Multiple Repository Calls Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/jdbc/transactions.adoc Use a service facade to define transactional boundaries for operations involving multiple repository calls. This ensures that all operations within the method are executed as a single atomic unit. ```java @Service public class UserManagementImpl implements UserManagement { private final UserRepository userRepository; private final RoleRepository roleRepository; UserManagementImpl(UserRepository userRepository, RoleRepository roleRepository) { this.userRepository = userRepository; this.roleRepository = roleRepository; } @Transactional public void addRoleToAllUsers(String roleName) { Role role = roleRepository.findByName(roleName); for (User user : userRepository.findAll()) { user.addRole(role); userRepository.save(user); } } } ``` -------------------------------- ### Configure Schema Drop Filters Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/jdbc/schema-support.adoc Configure filters for dropping tables and columns in differential schema updates. These filters allow fine-grained control over which schema elements can be removed. ```java writer.setDropTableFilter(tableName -> …); writer.setDropColumnFilter((tableName, columnName) -> …); ``` -------------------------------- ### Add Spring Milestone Repository Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/jdbc/getting-started.adoc Configure your Maven pom.xml to use the Spring Milestone repository for dependency resolution. ```xml spring-milestone Spring Maven MILESTONE Repository https://repo.spring.io/milestone ``` -------------------------------- ### Criteria Class Methods Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/commons/criteria-methods.adoc The Criteria class offers a set of methods that allow for the construction of query conditions, directly corresponding to SQL operators. ```APIDOC ## Criteria Methods The `Criteria` class provides the following methods, all of which correspond to SQL operators: * `Criteria` *and* `(String column)`: Adds a chained `Criteria` with the specified `property` to the current `Criteria` and returns the newly created one. * `Criteria` *or* `(String column)`: Adds a chained `Criteria` with the specified `property` to the current `Criteria` and returns the newly created one. * `Criteria` *greaterThan* `(Object o)`: Creates a criterion by using the `>` operator. * `Criteria` *greaterThanOrEquals* `(Object o)`: Creates a criterion by using the `>=` operator. * `Criteria` *in* `(Object... o)`: Creates a criterion by using the `IN` operator for a varargs argument. * `Criteria` *in* `(Collection collection)`: Creates a criterion by using the `IN` operator using a collection. * `Criteria` *is* `(Object o)`: Creates a criterion by using column matching (`property = value`). * `Criteria` *isNull* `()`: Creates a criterion by using the `IS NULL` operator. * `Criteria` *isNotNull* `()`: Creates a criterion by using the `IS NOT NULL` operator. * `Criteria` *lessThan* `(Object o)`: Creates a criterion by using the `<` operator. * `Criteria` *lessThanOrEquals* `(Object o)`: Creates a criterion by using the `<=` operator. * `Criteria` *like* `(Object o)`: Creates a criterion by using the `LIKE` operator without escape character processing. * `Criteria` *not* `(Object o)`: Creates a criterion by using the `!=` operator. * `Criteria` *notIn* `(Object... o)`: Creates a criterion by using the `NOT IN` operator for a varargs argument. * `Criteria` *notIn* `(Collection collection)`: Creates a criterion by using the `NOT IN` operator using a collection. ``` -------------------------------- ### Delete Data with R2DBC EntityTemplate Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/entity-persistence.adoc Demonstrates deleting Person entities using R2DBC. It supports specifying the table and a query to define the WHERE clause for deletion. ```java template.delete(Person.class) .from("persons") .matching(query(where("id").is(id))) .all(); ``` -------------------------------- ### Insert Data with R2DBC EntityTemplate Source: https://github.com/spring-projects/spring-data-relational/blob/main/src/main/antora/modules/ROOT/pages/r2dbc/entity-persistence.adoc Demonstrates how to insert a Person object using R2DBC's fluent API. The `into()` method infers the table name from the entity's mapping metadata. ```java Person person = new Person(id, name, age); template.insert(Person.class) .into("persons") .using(person); ```