Skip to content

Commit 57c199d

Browse files
committed
Merge pull request #14928 from nicce
* pr/14928: Polish "Enhance multiple entity manager factories how-to" Enhance multiple entity manager factories how-to Closes gh-14928
2 parents a1a2f00 + 03b65f3 commit 57c199d

File tree

3 files changed

+84
-36
lines changed

3 files changed

+84
-36
lines changed

spring-boot-project/spring-boot-docs/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ dependencies {
7979
implementation("org.assertj:assertj-core")
8080
implementation("org.glassfish.jersey.core:jersey-server")
8181
implementation("org.hibernate:hibernate-jcache")
82+
implementation("org.springframework:spring-orm")
8283
implementation("org.springframework:spring-test")
8384
implementation("org.springframework:spring-web")
8485
implementation("org.springframework:spring-webflux")

spring-boot-project/spring-boot-docs/src/docs/asciidoc/howto.adoc

Lines changed: 18 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1799,62 +1799,44 @@ Spring Boot auto-configuration switches off its entity manager in the presence o
17991799

18001800

18011801
[[howto-use-two-entity-managers]]
1802-
=== Use Two EntityManagers
1803-
Even if the default `EntityManagerFactory` works fine, you need to define a new one, otherwise the presence of the second bean of that type switches off the default.
1804-
You can use the `EntityManagerBuilder` provided by Spring Boot to help you to create one.
1805-
Alternatively, you can use the `LocalContainerEntityManagerFactoryBean` directly from Spring ORM, as shown in the following example:
1802+
[[howto-use-multiple-entity-managers]]
1803+
=== Using Multiple EntityManagerFactories
1804+
If you need to use JPA against multiple data sources, you likely need one `EntityManagerFactory` per data source.
1805+
The `LocalContainerEntityManagerFactoryBean` from Spring ORM allows you to configure an `EntityManagerFactory` for your needs.
1806+
You can also reuse `JpaProperties` to bind settings for each `EntityManagerFactory`, as shown in the following example:
18061807

18071808
[source,java,indent=0,subs="verbatim,quotes,attributes"]
18081809
----
1809-
// add two data sources configured as above
1810-
1811-
@Bean
1812-
public LocalContainerEntityManagerFactoryBean customerEntityManagerFactory(
1813-
EntityManagerFactoryBuilder builder) {
1814-
return builder
1815-
.dataSource(customerDataSource())
1816-
.packages(Customer.class)
1817-
.persistenceUnit("customers")
1818-
.build();
1819-
}
1820-
1821-
@Bean
1822-
public LocalContainerEntityManagerFactoryBean orderEntityManagerFactory(
1823-
EntityManagerFactoryBuilder builder) {
1824-
return builder
1825-
.dataSource(orderDataSource())
1826-
.packages(Order.class)
1827-
.persistenceUnit("orders")
1828-
.build();
1829-
}
1810+
include::{code-examples}/jpa/CustomEntityManagerFactoryExample.java[tag=configuration]
18301811
----
18311812

1813+
The example above creates an `EntityManagerFactory` using a `DataSource` bean named `firstDataSource`.
1814+
It scans entities located in the same package as `Order`.
1815+
It is possible to map additional JPA properties using the `app.first.jpa` namespace.
1816+
18321817
NOTE: When you create a bean for `LocalContainerEntityManagerFactoryBean` yourself, any customization that was applied during the creation of the auto-configured `LocalContainerEntityManagerFactoryBean` is lost.
18331818
For example, in case of Hibernate, any properties under the `spring.jpa.hibernate` prefix will not be automatically applied to your `LocalContainerEntityManagerFactoryBean`.
18341819
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.
1835-
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.
18361820

1837-
The configuration above almost works on its own.
1838-
To complete the picture, you need to configure `TransactionManagers` for the two `EntityManagers` as well.
1839-
If you mark one of them as `@Primary`, it could be picked up by the default `JpaTransactionManager` in Spring Boot.
1840-
The other would have to be explicitly injected into a new instance.
1821+
You should provide a similar configuration for any additional data sources for which you need JPA access.
1822+
To complete the picture, you need to configure a `JpaTransactionManager` for each `EntityManagerFactory` as well.
18411823
Alternatively, you might be able to use a JTA transaction manager that spans both.
18421824

18431825
If you use Spring Data, you need to configure `@EnableJpaRepositories` accordingly, as shown in the following example:
18441826

18451827
[source,java,indent=0,subs="verbatim,quotes,attributes"]
18461828
----
18471829
@Configuration(proxyBeanMethods = false)
1848-
@EnableJpaRepositories(basePackageClasses = Customer.class,
1849-
entityManagerFactoryRef = "customerEntityManagerFactory")
1850-
public class CustomerConfiguration {
1830+
@EnableJpaRepositories(basePackageClasses = Order.class,
1831+
entityManagerFactoryRef = "firstEntityManagerFactory")
1832+
public class OrderConfiguration {
18511833
...
18521834
}
18531835
18541836
@Configuration(proxyBeanMethods = false)
1855-
@EnableJpaRepositories(basePackageClasses = Order.class,
1856-
entityManagerFactoryRef = "orderEntityManagerFactory")
1857-
public class OrderConfiguration {
1837+
@EnableJpaRepositories(basePackageClasses = Customer.class,
1838+
entityManagerFactoryRef = "secondEntityManagerFactory")
1839+
public class CustomerConfiguration {
18581840
...
18591841
}
18601842
----
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright 2012-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.docs.jpa;
18+
19+
import javax.sql.DataSource;
20+
21+
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
22+
import org.springframework.boot.context.properties.ConfigurationProperties;
23+
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
24+
import org.springframework.context.annotation.Bean;
25+
import org.springframework.orm.jpa.JpaVendorAdapter;
26+
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
27+
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
28+
29+
/**
30+
* Example configuration for a custom JPA entity manager.
31+
*
32+
* @author Stephane Nicoll
33+
*/
34+
public class CustomEntityManagerFactoryExample {
35+
36+
// tag::configuration[]
37+
@Bean
38+
@ConfigurationProperties("app.jpa.first")
39+
public JpaProperties firstJpaProperties() {
40+
return new JpaProperties();
41+
}
42+
43+
@Bean
44+
public LocalContainerEntityManagerFactoryBean firstEntityManagerFactory(DataSource firstDataSource,
45+
JpaProperties firstJpaProperties) {
46+
EntityManagerFactoryBuilder builder = createEntityManagerFactoryBuilder(firstJpaProperties);
47+
return builder.dataSource(firstDataSource).packages(Order.class).persistenceUnit("firstDs").build();
48+
}
49+
50+
private EntityManagerFactoryBuilder createEntityManagerFactoryBuilder(JpaProperties jpaProperties) {
51+
JpaVendorAdapter jpaVendorAdapter = createJpaVendorAdapter(jpaProperties);
52+
return new EntityManagerFactoryBuilder(jpaVendorAdapter, jpaProperties.getProperties(), null);
53+
}
54+
55+
private JpaVendorAdapter createJpaVendorAdapter(JpaProperties jpaProperties) {
56+
// Map JPA properties as needed
57+
return new HibernateJpaVendorAdapter();
58+
}
59+
// end::configuration[]
60+
61+
private static class Order {
62+
63+
}
64+
65+
}

0 commit comments

Comments
 (0)