371 lines
20 KiB
Plaintext
371 lines
20 KiB
Plaintext
[[howto.data-access]]
|
|
== Data Access
|
|
Spring Boot includes a number of starters for working with data sources.
|
|
This section answers questions related to doing so.
|
|
|
|
|
|
|
|
[[howto.data-access.configure-custom-datasource]]
|
|
=== Configure a Custom DataSource
|
|
To configure your own `DataSource`, define a `@Bean` of that type in your configuration.
|
|
Spring Boot reuses your `DataSource` anywhere one is required, including database initialization.
|
|
If you need to externalize some settings, you can bind your `DataSource` to the environment (see "`<<features#features.external-config.typesafe-configuration-properties.third-party-configuration>>`").
|
|
|
|
The following example shows how to define a data source in a bean:
|
|
|
|
include::code:custom/MyDataSourceConfiguration[]
|
|
|
|
The following example shows how to define a data source by setting its properties:
|
|
|
|
[source,yaml,indent=0,subs="verbatim",configblocks]
|
|
----
|
|
app:
|
|
datasource:
|
|
url: "jdbc:h2:mem:mydb"
|
|
username: "sa"
|
|
pool-size: 30
|
|
----
|
|
|
|
Assuming that `SomeDataSource` has regular JavaBean properties for the URL, the username, and the pool size, these settings are bound automatically before the `DataSource` is made available to other components.
|
|
|
|
Spring Boot also provides a utility builder class, called `DataSourceBuilder`, that can be used to create one of the standard data sources (if it is on the classpath).
|
|
The builder can detect which one to use based on what is available on the classpath.
|
|
It also auto-detects the driver based on the JDBC URL.
|
|
|
|
The following example shows how to create a data source by using a `DataSourceBuilder`:
|
|
|
|
include::code:builder/MyDataSourceConfiguration[]
|
|
|
|
To run an app with that `DataSource`, all you need is the connection information.
|
|
Pool-specific settings can also be provided.
|
|
Check the implementation that is going to be used at runtime for more details.
|
|
|
|
The following example shows how to define a JDBC data source by setting properties:
|
|
|
|
[source,yaml,indent=0,subs="verbatim",configblocks]
|
|
----
|
|
app:
|
|
datasource:
|
|
url: "jdbc:mysql://localhost/test"
|
|
username: "dbuser"
|
|
password: "dbpass"
|
|
pool-size: 30
|
|
----
|
|
|
|
However, there is a catch due to the method's `DataSource` return type.
|
|
This hides the actual type of the connection pool so no configuration property metadata is generated for your custom `DataSource` and no auto-completion is available in your IDE.
|
|
To address this problem, use the builder's `type(Class)` method to specify the type of `DataSource` to be built and update the method's return type.
|
|
For example, the following shows how to create a `HikariDataSource` with `DataSourceBuilder`:
|
|
|
|
include::code:simple/MyDataSourceConfiguration[]
|
|
|
|
Unfortunately, this basic setup does not work because Hikari has no `url` property.
|
|
Instead, it has a `jdbc-url` property which means that you must rewrite your configuration as follows:
|
|
|
|
[source,yaml,indent=0,subs="verbatim",configblocks]
|
|
----
|
|
app:
|
|
datasource:
|
|
jdbc-url: "jdbc:mysql://localhost/test"
|
|
username: "dbuser"
|
|
password: "dbpass"
|
|
pool-size: 30
|
|
----
|
|
|
|
To address this problem, make use of `DataSourceProperties` which will handle the `url` to `jdbc-url` translation for you.
|
|
You can initialize a `DataSourceBuilder` from the state of any `DataSourceProperties` object using its `initializeDataSourceBuilder()` method.
|
|
You could inject the `DataSourceProperties` that Spring Boot creates automatically, however, that would split your configuration across `+spring.datasource.*+` and `+app.datasource.*+`.
|
|
To avoid this, define a custom `DataSourceProperties` with a custom configuration properties prefix, as shown in the following example:
|
|
|
|
include::code:configurable/MyDataSourceConfiguration[]
|
|
|
|
This setup is equivalent to what Spring Boot does for you by default, except that the pool's type is specified in code and its settings are exposed as `app.datasource.configuration.*` properties.
|
|
`DataSourceProperties` takes care of the `url` to `jdbc-url` translation, so you can configure it as follows:
|
|
|
|
[source,yaml,indent=0,subs="verbatim",configblocks]
|
|
----
|
|
app:
|
|
datasource:
|
|
url: "jdbc:mysql://localhost/test"
|
|
username: "dbuser"
|
|
password: "dbpass"
|
|
configuration:
|
|
maximum-pool-size: 30
|
|
----
|
|
|
|
Note that, as the custom configuration specifies in code that Hikari should be used, `app.datasource.type` will have no effect.
|
|
|
|
As described in "`<<data#data.sql.datasource.connection-pool>>`", `DataSourceBuilder` supports several different connection pools.
|
|
To use a pool other than Hikari, add it to the classpath, use the `type(Class)` method to specify the pool class to use, and update the `@Bean` method's return type to match.
|
|
This will also provide you with configuration property metadata for the specific connection pool that you've chosen.
|
|
|
|
TIP: Spring Boot will expose Hikari-specific settings to `spring.datasource.hikari`.
|
|
This example uses a more generic `configuration` sub namespace as the example does not support multiple datasource implementations.
|
|
|
|
See "`<<data#data.sql.datasource>>`" and the {spring-boot-autoconfigure-module-code}/jdbc/DataSourceAutoConfiguration.java[`DataSourceAutoConfiguration`] class for more details.
|
|
|
|
|
|
|
|
[[howto.data-access.configure-two-datasources]]
|
|
=== Configure Two DataSources
|
|
If you need to configure multiple data sources, you can apply the same tricks that were described in the previous section.
|
|
You must, however, mark one of the `DataSource` instances as `@Primary`, because various auto-configurations down the road expect to be able to get one by type.
|
|
|
|
If you create your own `DataSource`, the auto-configuration backs off.
|
|
In the following example, we provide the _exact_ same feature set as the auto-configuration provides on the primary data source:
|
|
|
|
include::code:MyDataSourcesConfiguration[]
|
|
|
|
TIP: `firstDataSourceProperties` has to be flagged as `@Primary` so that the database initializer feature uses your copy (if you use the initializer).
|
|
|
|
Both data sources are also bound for advanced customizations.
|
|
For instance, you could configure them as follows:
|
|
|
|
[source,yaml,indent=0,subs="verbatim",configblocks]
|
|
----
|
|
app:
|
|
datasource:
|
|
first:
|
|
url: "jdbc:mysql://localhost/first"
|
|
username: "dbuser"
|
|
password: "dbpass"
|
|
configuration:
|
|
maximum-pool-size: 30
|
|
|
|
second:
|
|
url: "jdbc:mysql://localhost/second"
|
|
username: "dbuser"
|
|
password: "dbpass"
|
|
max-total: 30
|
|
----
|
|
|
|
You can apply the same concept to the secondary `DataSource` as well, as shown in the following example:
|
|
|
|
include::code:MyCompleteDataSourcesConfiguration[]
|
|
|
|
The preceding example configures two data sources on custom configuration property namespaces with the same logic as Spring Boot would use in auto-configuration.
|
|
Note that each `configuration` sub namespace provides advanced settings based on the chosen implementation.
|
|
|
|
As with <<#howto.data-access.configure-custom-datasource,configuring a single custom `DataSource`>>, the type of one or both of the `DataSource` beans can be customized using the `type(Class)` method on `DataSourceBuilder`.
|
|
See "`<<data#data.sql.datasource.connection-pool>>`" for details of the supported types.
|
|
|
|
|
|
|
|
[[howto.data-access.spring-data-repositories]]
|
|
=== Use Spring Data Repositories
|
|
Spring Data can create implementations of `Repository` interfaces of various flavors.
|
|
Spring Boot handles all of that for you, as long as those `Repository` implementations are included in one of the <<using#using.auto-configuration.packages,auto-configuration packages>>, typically the package (or a sub-package) of your main application class that is annotated with `@SpringBootApplication` or `@EnableAutoConfiguration`.
|
|
|
|
For many applications, all you need is to put the right Spring Data dependencies on your classpath.
|
|
There is a `spring-boot-starter-data-jpa` for JPA, `spring-boot-starter-data-mongodb` for Mongodb, and various other starters for supported technologies.
|
|
To get started, create some repository interfaces to handle your `@Entity` objects.
|
|
|
|
Spring Boot determines the location of your `Repository` implementations by scanning the <<using#using.auto-configuration.packages,auto-configuration packages>>.
|
|
For more control, use the `@Enable…Repositories` annotations from Spring Data.
|
|
|
|
For more about Spring Data, see the {spring-data}[Spring Data project page].
|
|
|
|
|
|
|
|
[[howto.data-access.separate-entity-definitions-from-spring-configuration]]
|
|
=== Separate @Entity Definitions from Spring Configuration
|
|
Spring Boot determines the location of your `@Entity` definitions by scanning the <<using#using.auto-configuration.packages,auto-configuration packages>>.
|
|
For more control, use the `@EntityScan` annotation, as shown in the following example:
|
|
|
|
include::code:MyApplication[]
|
|
|
|
|
|
|
|
[[howto.data-access.jpa-properties]]
|
|
=== Configure JPA Properties
|
|
Spring Data JPA already provides some vendor-independent configuration options (such as those for SQL logging), and Spring Boot exposes those options and a few more for Hibernate as external configuration properties.
|
|
Some of them are automatically detected according to the context so you should not have to set them.
|
|
|
|
The `spring.jpa.hibernate.ddl-auto` is a special case, because, depending on runtime conditions, it has different defaults.
|
|
If an embedded database is used and no schema manager (such as Liquibase or Flyway) is handling the `DataSource`, it defaults to `create-drop`.
|
|
In all other cases, it defaults to `none`.
|
|
|
|
The dialect to use is detected by the JPA provider.
|
|
If you prefer to set the dialect yourself, set the configprop:spring.jpa.database-platform[] property.
|
|
|
|
The most common options to set are shown in the following example:
|
|
|
|
[source,yaml,indent=0,subs="verbatim",configprops,configblocks]
|
|
----
|
|
spring:
|
|
jpa:
|
|
hibernate:
|
|
naming:
|
|
physical-strategy: "com.example.MyPhysicalNamingStrategy"
|
|
show-sql: true
|
|
----
|
|
|
|
In addition, all properties in `+spring.jpa.properties.*+` are passed through as normal JPA properties (with the prefix stripped) when the local `EntityManagerFactory` is created.
|
|
|
|
[WARNING]
|
|
====
|
|
You need to ensure that names defined under `+spring.jpa.properties.*+` exactly match those expected by your JPA provider.
|
|
Spring Boot will not attempt any kind of relaxed binding for these entries.
|
|
|
|
For example, if you want to configure Hibernate's batch size you must use `+spring.jpa.properties.hibernate.jdbc.batch_size+`.
|
|
If you use other forms, such as `batchSize` or `batch-size`, Hibernate will not apply the setting.
|
|
====
|
|
|
|
TIP: If you need to apply advanced customization to Hibernate properties, consider registering a `HibernatePropertiesCustomizer` bean that will be invoked prior to creating the `EntityManagerFactory`.
|
|
This takes precedence over anything that is applied by the auto-configuration.
|
|
|
|
|
|
|
|
[[howto.data-access.configure-hibernate-naming-strategy]]
|
|
=== Configure Hibernate Naming Strategy
|
|
Hibernate uses {hibernate-docs}#naming[two different naming strategies] to map names from the object model to the corresponding database names.
|
|
The fully qualified class name of the physical and the implicit strategy implementations can be configured by setting the `spring.jpa.hibernate.naming.physical-strategy` and `spring.jpa.hibernate.naming.implicit-strategy` properties, respectively.
|
|
Alternatively, if `ImplicitNamingStrategy` or `PhysicalNamingStrategy` beans are available in the application context, Hibernate will be automatically configured to use them.
|
|
|
|
By default, Spring Boot configures the physical naming strategy with `CamelCaseToUnderscoresNamingStrategy`.
|
|
Using this strategy, all dots are replaced by underscores and camel casing is replaced by underscores as well.
|
|
Additionally, by default, all table names are generated in lower case.
|
|
For example, a `TelephoneNumber` entity is mapped to the `telephone_number` table.
|
|
If your schema requires mixed-case identifiers, define a custom `CamelCaseToUnderscoresNamingStrategy` bean, as shown in the following example:
|
|
|
|
include::code:spring/MyHibernateConfiguration[]
|
|
|
|
If you prefer to use Hibernate's default instead, set the following property:
|
|
|
|
[indent=0,properties,subs="verbatim"]
|
|
----
|
|
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
|
|
----
|
|
|
|
Alternatively, you can configure the following bean:
|
|
|
|
include::code:standard/MyHibernateConfiguration[]
|
|
|
|
See {spring-boot-autoconfigure-module-code}/orm/jpa/HibernateJpaAutoConfiguration.java[`HibernateJpaAutoConfiguration`] and {spring-boot-autoconfigure-module-code}/orm/jpa/JpaBaseConfiguration.java[`JpaBaseConfiguration`] for more details.
|
|
|
|
|
|
|
|
[[howto.data-access.configure-hibernate-second-level-caching]]
|
|
=== Configure Hibernate Second-Level Caching
|
|
Hibernate {hibernate-docs}#caching[second-level cache] can be configured for a range of cache providers.
|
|
Rather than configuring Hibernate to lookup the cache provider again, it is better to provide the one that is available in the context whenever possible.
|
|
|
|
To do this with JCache, first make sure that `org.hibernate.orm:hibernate-jcache` is available on the classpath.
|
|
Then, add a `HibernatePropertiesCustomizer` bean as shown in the following example:
|
|
|
|
include::code:MyHibernateSecondLevelCacheConfiguration[]
|
|
|
|
This customizer will configure Hibernate to use the same `CacheManager` as the one that the application uses.
|
|
It is also possible to use separate `CacheManager` instances.
|
|
For details, see {hibernate-docs}#caching-provider-jcache[the Hibernate user guide].
|
|
|
|
|
|
|
|
[[howto.data-access.dependency-injection-in-hibernate-components]]
|
|
=== Use Dependency Injection in Hibernate Components
|
|
By default, Spring Boot registers a `BeanContainer` implementation that uses the `BeanFactory` so that converters and entity listeners can use regular dependency injection.
|
|
|
|
You can disable or tune this behavior by registering a `HibernatePropertiesCustomizer` that removes or changes the `hibernate.resource.beans.container` property.
|
|
|
|
|
|
|
|
[[howto.data-access.use-custom-entity-manager]]
|
|
=== Use a Custom EntityManagerFactory
|
|
To take full control of the configuration of the `EntityManagerFactory`, you need to add a `@Bean` named '`entityManagerFactory`'.
|
|
Spring Boot auto-configuration switches off its entity manager in the presence of a bean of that type.
|
|
|
|
|
|
|
|
[[howto.data-access.use-multiple-entity-managers]]
|
|
[[howto.data-access.use-multiple-entity-managers]]
|
|
=== Using Multiple EntityManagerFactories
|
|
If you need to use JPA against multiple data sources, you likely need one `EntityManagerFactory` per data source.
|
|
The `LocalContainerEntityManagerFactoryBean` from Spring ORM allows you to configure an `EntityManagerFactory` for your needs.
|
|
You can also reuse `JpaProperties` to bind settings for each `EntityManagerFactory`, as shown in the following example:
|
|
|
|
include::code:MyEntityManagerFactoryConfiguration[]
|
|
|
|
The example above creates an `EntityManagerFactory` using a `DataSource` bean named `firstDataSource`.
|
|
It scans entities located in the same package as `Order`.
|
|
It is possible to map additional JPA properties using the `app.first.jpa` namespace.
|
|
|
|
NOTE: When you create a bean for `LocalContainerEntityManagerFactoryBean` yourself, any customization that was applied during the creation of the auto-configured `LocalContainerEntityManagerFactoryBean` is lost.
|
|
For example, in the case of Hibernate, any properties under the `spring.jpa.hibernate` prefix will not be automatically applied to your `LocalContainerEntityManagerFactoryBean`.
|
|
If you were relying on these properties for configuring things like the naming strategy or the DDL mode, you will need to explicitly configure that when creating the `LocalContainerEntityManagerFactoryBean` bean.
|
|
|
|
You should provide a similar configuration for any additional data sources for which you need JPA access.
|
|
To complete the picture, you need to configure a `JpaTransactionManager` for each `EntityManagerFactory` as well.
|
|
Alternatively, you might be able to use a JTA transaction manager that spans both.
|
|
|
|
If you use Spring Data, you need to configure `@EnableJpaRepositories` accordingly, as shown in the following examples:
|
|
|
|
include::code:OrderConfiguration[]
|
|
|
|
include::code:CustomerConfiguration[]
|
|
|
|
|
|
|
|
[[howto.data-access.use-traditional-persistence-xml]]
|
|
=== Use a Traditional persistence.xml File
|
|
Spring Boot will not search for or use a `META-INF/persistence.xml` by default.
|
|
If you prefer to use a traditional `persistence.xml`, you need to define your own `@Bean` of type `LocalEntityManagerFactoryBean` (with an ID of '`entityManagerFactory`') and set the persistence unit name there.
|
|
|
|
See {spring-boot-autoconfigure-module-code}/orm/jpa/JpaBaseConfiguration.java[`JpaBaseConfiguration`] for the default settings.
|
|
|
|
|
|
|
|
[[howto.data-access.use-spring-data-jpa-and-mongo-repositories]]
|
|
=== Use Spring Data JPA and Mongo Repositories
|
|
Spring Data JPA and Spring Data Mongo can both automatically create `Repository` implementations for you.
|
|
If they are both present on the classpath, you might have to do some extra configuration to tell Spring Boot which repositories to create.
|
|
The most explicit way to do that is to use the standard Spring Data `+@EnableJpaRepositories+` and `+@EnableMongoRepositories+` annotations and provide the location of your `Repository` interfaces.
|
|
|
|
There are also flags (`+spring.data.*.repositories.enabled+` and `+spring.data.*.repositories.type+`) that you can use to switch the auto-configured repositories on and off in external configuration.
|
|
Doing so is useful, for instance, in case you want to switch off the Mongo repositories and still use the auto-configured `MongoTemplate`.
|
|
|
|
The same obstacle and the same features exist for other auto-configured Spring Data repository types (Elasticsearch, Redis, and others).
|
|
To work with them, change the names of the annotations and flags accordingly.
|
|
|
|
|
|
|
|
[[howto.data-access.customize-spring-data-web-support]]
|
|
=== Customize Spring Data's Web Support
|
|
Spring Data provides web support that simplifies the use of Spring Data repositories in a web application.
|
|
Spring Boot provides properties in the `spring.data.web` namespace for customizing its configuration.
|
|
Note that if you are using Spring Data REST, you must use the properties in the `spring.data.rest` namespace instead.
|
|
|
|
|
|
|
|
[[howto.data-access.exposing-spring-data-repositories-as-rest]]
|
|
=== Expose Spring Data Repositories as REST Endpoint
|
|
Spring Data REST can expose the `Repository` implementations as REST endpoints for you,
|
|
provided Spring MVC has been enabled for the application.
|
|
|
|
Spring Boot exposes a set of useful properties (from the `spring.data.rest` namespace) that customize the {spring-data-rest-api}/core/config/RepositoryRestConfiguration.html[`RepositoryRestConfiguration`].
|
|
If you need to provide additional customization, you should use a {spring-data-rest-api}/webmvc/config/RepositoryRestConfigurer.html[`RepositoryRestConfigurer`] bean.
|
|
|
|
NOTE: If you do not specify any order on your custom `RepositoryRestConfigurer`, it runs after the one Spring Boot uses internally.
|
|
If you need to specify an order, make sure it is higher than 0.
|
|
|
|
|
|
|
|
[[howto.data-access.configure-a-component-that-is-used-by-jpa]]
|
|
=== Configure a Component that is Used by JPA
|
|
If you want to configure a component that JPA uses, then you need to ensure that the component is initialized before JPA.
|
|
When the component is auto-configured, Spring Boot takes care of this for you.
|
|
For example, when Flyway is auto-configured, Hibernate is configured to depend on Flyway so that Flyway has a chance to initialize the database before Hibernate tries to use it.
|
|
|
|
If you are configuring a component yourself, you can use an `EntityManagerFactoryDependsOnPostProcessor` subclass as a convenient way of setting up the necessary dependencies.
|
|
For example, if you use Hibernate Search with Elasticsearch as its index manager, any `EntityManagerFactory` beans must be configured to depend on the `elasticsearchClient` bean, as shown in the following example:
|
|
|
|
include::code:ElasticsearchEntityManagerFactoryDependsOnPostProcessor[]
|
|
|
|
|
|
|
|
[[howto.data-access.configure-jooq-with-multiple-datasources]]
|
|
=== Configure jOOQ with Two DataSources
|
|
If you need to use jOOQ with multiple data sources, you should create your own `DSLContext` for each one.
|
|
See {spring-boot-autoconfigure-module-code}/jooq/JooqAutoConfiguration.java[JooqAutoConfiguration] for more details.
|
|
|
|
TIP: In particular, `JooqExceptionTranslator` and `SpringTransactionProvider` can be reused to provide similar features to what the auto-configuration does with a single `DataSource`.
|