Reputation: 780
I'm using SpringBoot 2.7.0 and trying to set an entity manager cause I have 2 databases.
But the entityManager that I instantiated doesn't work like default one.
I configured it with below code.
@Slf4j
@RequiredArgsConstructor
@EnableJpaAuditing
@EnableJpaRepositories(basePackages = "com.xxx.yyy", entityManagerFactoryRef = "businessEntityManagerFactory", transactionManagerRef = "businessTransactionManager")
@EntityScan(basePackages = "com.xxx.yyy")
@Configuration
public class JpaConfiguration {
@Bean
public LocalContainerEntityManagerFactoryBean businessEntityManagerFactory(EntityManagerFactoryBuilder builder,
DataSource businessDataSource) {
return builder
.dataSource(businessDataSource)
.packages("com.xxx.yyy")
.build();
}
@Bean
public PlatformTransactionManager businessTransactionManager(LocalContainerEntityManagerFactoryBean businessEntityManagerFactory) {
return new JpaTransactionManager(Objects.requireNonNull(businessEntityManagerFactory.getObject()));
}
}
Does anyone know how I can instantiate an entity manager with same settings like spring boot default one?
Upvotes: 1
Views: 4130
Reputation: 780
Sven's answer might be right but I didn't try it because I saw this after I found the solution and it looked requiring many changes my codes.
I figured this out with below codes
@Bean
public LocalContainerEntityManagerFactoryBean businessEntityManagerFactory(DataSource businessDataSource) {
LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(businessDataSource);
emf.setPackagesToScan("com.xxx.yyy");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setShowSql(Boolean.valueOf(env.getProperty("spring.jpa.show-sql")));
emf.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.dialect", env.getProperty("spring.jpa.properties.hibernate.dialect"));
properties.put("hibernate.format_sql", env.getProperty("spring.jpa.properties.hibernate.format_sql"));
properties.put("hibernate.hbm2ddl.auto", env.getProperty("spring.jpa.properties.hibernate.hbm2ddl.auto"));
properties.put("hibernate.physical_naming_strategy", "org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy");
properties.put("hibernate.implicit_naming_strategy", "org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy");
emf.setJpaPropertyMap(properties);
return emf;
}
Upvotes: 2
Reputation: 4368
Spring's convention-over-configuration does not work well with multiple database configurations.
Particuallary the configuration has to be autowired "manually". That's the reason springt.jpa.show-sql
is not considered.
I will post an example on how to configure a database "manually".
import java.util.Map;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
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.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager;
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.zaxxer.hikari.HikariDataSource;
@Configuration
@EnableTransactionManagement
@EnableAutoConfiguration(exclude = {JdbcRepositoriesAutoConfiguration.class, JpaRepositoriesAutoConfiguration.class, DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class, JdbcTemplateAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
@EnableJpaRepositories(basePackageClasses = {ExampleXyzRepository.class}, transactionManagerRef = DatabaseConfig.SPRING_TRANSACTION_MANAGER)
public class DatabaseConfig {
public static final String SPRING_TRANSACTION_MANAGER = "springTransactionManager";
private static LocalContainerEntityManagerFactoryBean createEntityManagerFactory(
final ObjectProvider<PersistenceUnitManager> persistenceUnitManagerProvider, final JpaProperties jpaProperties,
final HibernateProperties hibernateProperties, final DataSource dataSource, final Class<?> exampleEntityClass, final String persistenceUnit) {
return createEntityManagerFactoryBuilder(persistenceUnitManagerProvider.getIfAvailable(), jpaProperties, hibernateProperties)
.dataSource(dataSource)
.packages(exampleEntityClass)
.persistenceUnit(persistenceUnit)
.build();
}
private static EntityManagerFactoryBuilder createEntityManagerFactoryBuilder(
final PersistenceUnitManager persistenceUnitManager, final JpaProperties jpaProperties, final HibernateProperties hibernateProperties) {
final JpaVendorAdapter jpaVendorAdapter = createJpaVendorAdapter(jpaProperties);
final Map<String, Object> expandedProperties = hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
return new EntityManagerFactoryBuilder(jpaVendorAdapter, expandedProperties, persistenceUnitManager);
}
private static JpaVendorAdapter createJpaVendorAdapter(final JpaProperties jpaProperties) {
final AbstractJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setShowSql(jpaProperties.isShowSql());
adapter.setDatabasePlatform(jpaProperties.getDatabasePlatform());
adapter.setGenerateDdl(jpaProperties.isGenerateDdl());
if (jpaProperties.getDatabase() != null) {
adapter.setDatabase(jpaProperties.getDatabase());
}
return adapter;
}
private static HikariDataSource initializeDataSource(final DataSourceProperties dataSourceProperties) {
return dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
}
@Bean
@ConfigurationProperties("spring.datasource")
public DataSourceProperties springDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@ConfigurationProperties("spring.datasource.hikari")
public DataSource springDataSource(@Qualifier("springDataSourceProperties") final DataSourceProperties springDataSourceProperties) {
return initializeDataSource(springDataSourceProperties);
}
@Bean
@ConfigurationProperties("spring.jpa")
public JpaProperties springJpaProperties() {
return new JpaProperties();
}
@Bean
@ConfigurationProperties("spring.jpa.hibernate")
public HibernateProperties springHibernateProperties() {
return new HibernateProperties();
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
final ObjectProvider<PersistenceUnitManager> persistenceUnitManagerProvider,
@Qualifier("springJpaProperties") final JpaProperties springJpaProperties,
@Qualifier("springHibernateProperties") final HibernateProperties springHibernateProperties,
@Qualifier("springDataSource") final DataSource springDataSource) {
return createEntityManagerFactory(persistenceUnitManagerProvider, springJpaProperties, springHibernateProperties, springDataSource, ExampleXyzEntity.class, "default-persistence-unit");
}
@Bean(SPRING_TRANSACTION_MANAGER)
public JpaTransactionManager transactionManager(@Qualifier("entityManagerFactory") final EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
}
See how the configuration of DataSourceProperties
, HibernateProperties
, DataSource
and JpaProperties
are bound.
The second database is configured similar.
But:
spring.jpa
and spring.datasource
- obviouslytransactionManager
in the org.springframework.transaction.annotation.Transactional
while accessing the second database, e.g. in the CrudRepository
Upvotes: 1