Commit 03b65f32 authored by Stephane Nicoll's avatar Stephane Nicoll

Polish "Enhance multiple entity manager factories how-to"

See gh-14928
parent 0d9db46f
...@@ -79,6 +79,7 @@ dependencies { ...@@ -79,6 +79,7 @@ dependencies {
implementation("org.assertj:assertj-core") implementation("org.assertj:assertj-core")
implementation("org.glassfish.jersey.core:jersey-server") implementation("org.glassfish.jersey.core:jersey-server")
implementation("org.hibernate:hibernate-jcache") implementation("org.hibernate:hibernate-jcache")
implementation("org.springframework:spring-orm")
implementation("org.springframework:spring-test") implementation("org.springframework:spring-test")
implementation("org.springframework:spring-web") implementation("org.springframework:spring-web")
implementation("org.springframework:spring-webflux") implementation("org.springframework:spring-webflux")
......
...@@ -1798,47 +1798,28 @@ Spring Boot auto-configuration switches off its entity manager in the presence o ...@@ -1798,47 +1798,28 @@ Spring Boot auto-configuration switches off its entity manager in the presence o
[[howto-use-two-entity-managers]]
[[howto-use-multiple-entity-managers]] [[howto-use-multiple-entity-managers]]
=== Using Multiple EntityManagerFactories === Using Multiple EntityManagerFactories
Sometimes you may wish to work with multiple Entity Manager Factories, because you have multiple data sources. If you need to use JPA against multiple data sources, you likely need one `EntityManagerFactory` per data source.
In those cases, you need to create your own `EntityManagerFactory` for each datasource. The `LocalContainerEntityManagerFactoryBean` from Spring ORM allows you to configure an `EntityManagerFactory` for your needs.
You can use the `EntityManagerBuilder` provided by Spring Boot to help you to create one. You can also reuse `JpaProperties` to bind settings for each `EntityManagerFactory`, as shown in the following example:
Alternatively, you can use the `LocalContainerEntityManagerFactoryBean` directly from Spring ORM, as shown in the following example:
[source,java,indent=0,subs="verbatim,quotes,attributes"] [source,java,indent=0,subs="verbatim,quotes,attributes"]
---- ----
// add two data sources configured as above include::{code-examples}/jpa/CustomEntityManagerFactoryExample.java[tag=configuration]
@Bean
public LocalContainerEntityManagerFactoryBean customerEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
return builder
.dataSource(customerDataSource())
.packages(Customer.class)
.persistenceUnit("customers")
.build();
}
@Bean
public LocalContainerEntityManagerFactoryBean orderEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
return builder
.dataSource(orderDataSource())
.packages(Order.class)
.persistenceUnit("orders")
.build();
}
---- ----
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. 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 case of Hibernate, any properties under the `spring.jpa.hibernate` prefix will not be automatically applied to your `LocalContainerEntityManagerFactoryBean`. For example, in 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. 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.
On the other hand, properties that get applied to the auto-configured `EntityManagerFactoryBuilder`, which are specified via `spring.jpa.properties`, will automatically be applied, provided you use the auto-configured `EntityManagerFactoryBuilder` to build the `LocalContainerEntityManagerFactoryBean` bean.
The configuration above almost works on its own. 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 `TransactionManagers` for the two `EntityManagers` as well. To complete the picture, you need to configure a `JpaTransactionManager` for each `EntityManagerFactory` as well.
If you mark one of them as `@Primary`, it could be picked up by the default `JpaTransactionManager` in Spring Boot.
The other would have to be explicitly injected into a new instance.
Alternatively, you might be able to use a JTA transaction manager that spans both. 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 example: If you use Spring Data, you need to configure `@EnableJpaRepositories` accordingly, as shown in the following example:
...@@ -1846,16 +1827,16 @@ If you use Spring Data, you need to configure `@EnableJpaRepositories` according ...@@ -1846,16 +1827,16 @@ If you use Spring Data, you need to configure `@EnableJpaRepositories` according
[source,java,indent=0,subs="verbatim,quotes,attributes"] [source,java,indent=0,subs="verbatim,quotes,attributes"]
---- ----
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(basePackageClasses = Customer.class, @EnableJpaRepositories(basePackageClasses = Order.class,
entityManagerFactoryRef = "customerEntityManagerFactory") entityManagerFactoryRef = "firstEntityManagerFactory")
public class CustomerConfiguration { public class OrderConfiguration {
... ...
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@EnableJpaRepositories(basePackageClasses = Order.class, @EnableJpaRepositories(basePackageClasses = Customer.class,
entityManagerFactoryRef = "orderEntityManagerFactory") entityManagerFactoryRef = "secondEntityManagerFactory")
public class OrderConfiguration { public class CustomerConfiguration {
... ...
} }
---- ----
......
/*
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.docs.jpa;
import javax.sql.DataSource;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
/**
* Example configuration for a custom JPA entity manager.
*
* @author Stephane Nicoll
*/
public class CustomEntityManagerFactoryExample {
// tag::configuration[]
@Bean
@ConfigurationProperties("app.jpa.first")
public JpaProperties firstJpaProperties() {
return new JpaProperties();
}
@Bean
public LocalContainerEntityManagerFactoryBean firstEntityManagerFactory(DataSource firstDataSource,
JpaProperties firstJpaProperties) {
EntityManagerFactoryBuilder builder = createEntityManagerFactoryBuilder(firstJpaProperties);
return builder.dataSource(firstDataSource).packages(Order.class).persistenceUnit("firstDs").build();
}
private EntityManagerFactoryBuilder createEntityManagerFactoryBuilder(JpaProperties jpaProperties) {
JpaVendorAdapter jpaVendorAdapter = createJpaVendorAdapter(jpaProperties);
return new EntityManagerFactoryBuilder(jpaVendorAdapter, jpaProperties.getProperties(), null);
}
private JpaVendorAdapter createJpaVendorAdapter(JpaProperties jpaProperties) {
// Map JPA properties as needed
return new HibernateJpaVendorAdapter();
}
// end::configuration[]
private static class Order {
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment