How to reconfigure LocalContainerEntityManagerFactoryBean in test - spring

If I have a programmatically managed LocalContainerEntityManagerFactoryBean, like with a #Bean-annotated method:
#Configuration
#EnableJpaRepositories(
entityManagerFactoryRef = "myEntityManager",
transactionManagerRef = "myTransactionManager",
basePackages = {"com.mycompany.my.repository"}
)
public class MyDbConfig {
#Bean
public LocalContainerEntityManagerFactoryBean mcEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
//some production config here
return em;
}
}
How do I add this little JPA property only to be used for integration testing, ideally via something like a listener below (in the test classpath)
public class AfterAllBeansCreatedListener {
#Autowired
private LocalContainerEntityManagerFactoryBean em
#PostConstruct
private void reconfigure() {
HashMap<String, Object> properties = em.getJpaPropertyMap()
properties.put("hibernate.hbm2ddl.auto", "create");
em.setJpaPropertyMap(properties);
}
}
Currently, I am using another #Bean-annotated method producing LocalContainerEntityManagerFactoryBean in a nested #TestConfiguration, but this means that I need to duplicate all the other creation logic for that bean, which is of course pure evil.

The quick and simple solution is to create a Map of properties within the mcEntityManager() method like so
#Configuration
#EnableJpaRepositories(
entityManagerFactoryRef = "myEntityManager",
transactionManagerRef = "myTransactionManager",
basePackages = {"com.mycompany.my.repository"}
)
public class MyDbConfig {
#Bean
public LocalContainerEntityManagerFactoryBean mcEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
HashMap<String, Object> properties = em.getJpaPropertyMap()
properties.put("hibernate.hbm2ddl.auto", "create");
em.setJpaPropertyMap(properties);
return em;
}
}
If you need different JpaProperty map values per env, you'd move the property map creatation to it's own Profile specific methods, like
#Bean
#Profile("dev)
public Map<String,Object> getMyJpaPropertyMap() {
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", "create");
properties.put("hibernate.temp.use_jdbc_metadata_defaults",false);
properties.put("hibernate.jdbc.lob.non_contextual_creation",true);
}
#Bean
#Profile("prod)
public Map<String,Object> getMyJpaPropertyMap() {
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", "update");
properties.put("hibernate.temp.use_jdbc_metadata_defaults",true);
}
and the mcEntityManager() method is updated to
#Bean
public LocalContainerEntityManagerFactoryBean mcEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setJpaPropertyMap(getMyJpaPropertyMap());
return em;
}

Related

SpringBoot multiple datasources Junit test fails with H2

I have a springboot project which requests data from 2 datasources (2 MariaDB SQL databases) and I have successfully implemented it by creating 2 configuration classes for each DB and their respective Beans. My DB used by default is the User DB (#Primary annotation used in its config class).
I want to test my user repository layer by using an H2 database and for that, I have created a configuration class for this datasource and declared the datasource properties in my application-test.properties file.
The problem is when I run my tests, I have a BeanDefinitionOverrideException saying that there's a collision of my bean names for my 1th DB and H2 DB (a bean with this name already exist...) since they use the same JPA repository package.
How can I use H2 database for my tests and tell Spring to not load the beans for my 2 MariaDB datasources ?
**Configuration of the 1th DB :
**
#Configuration
#EnableJpaRepositories(
basePackages = "com.baeldung.multipledb.dao.user",
entityManagerFactoryRef = "userEntityManager",
transactionManagerRef = "userTransactionManager"
)
public class PersistenceUserConfiguration {
#Autowired
private Environment env;
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean userEntityManager() {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(userDataSource());
em.setPackagesToScan(
new String[] { "com.baeldung.multipledb.model.user" });
HibernateJpaVendorAdapter vendorAdapter
= new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto",
env.getProperty("hibernate.hbm2ddl.auto"));
properties.put("hibernate.dialect",
env.getProperty("hibernate.dialect"));
em.setJpaPropertyMap(properties);
return em;
}
#Primary
#Bean
public DataSource userDataSource() {
DriverManagerDataSource dataSource
= new DriverManagerDataSource();
dataSource.setDriverClassName(
env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("user.jdbc.url"));
dataSource.setUsername(env.getProperty("jdbc.user"));
dataSource.setPassword(env.getProperty("jdbc.pass"));
return dataSource;
}
#Primary
#Bean
public PlatformTransactionManager userTransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
userEntityManager().getObject());
return transactionManager;
}
}
**Configuration of the 2nd DB :
**
#Configuration
#EnableJpaRepositories(
basePackages = "com.baeldung.multipledb.dao.product",
entityManagerFactoryRef = "productEntityManager",
transactionManagerRef = "productTransactionManager"
)
public class PersistenceProductConfiguration {
#Autowired
private Environment env;
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean productEntityManager() {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(productDataSource());
em.setPackagesToScan(
new String[] { "com.baeldung.multipledb.model.product" });
HibernateJpaVendorAdapter vendorAdapter
= new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto",
env.getProperty("hibernate.hbm2ddl.auto"));
properties.put("hibernate.dialect",
env.getProperty("hibernate.dialect"));
em.setJpaPropertyMap(properties);
return em;
}
#Primary
#Bean
public DataSource productDataSource() {
DriverManagerDataSource dataSource
= new DriverManagerDataSource();
dataSource.setDriverClassName(
env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("product.jdbc.url"));
dataSource.setproductname(env.getProperty("jdbc.product"));
dataSource.setPassword(env.getProperty("jdbc.pass"));
return dataSource;
}
#Primary
#Bean
public PlatformTransactionManager productTransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
productEntityManager().getObject());
return transactionManager;
}
}
}
**Configuration of H2 DB for tests :
**
#Profile("test")
#Configuration
#EnableJpaRepositories(
basePackages = "com.baeldung.multipledb.dao.user",
entityManagerFactoryRef = "h2EntityManager",
transactionManagerRef = "h2TransactionManager"
)
public class PersistenceH2Configuration {
#Autowired
private Environment env;
#Bean
public LocalContainerEntityManagerFactoryBean h2EntityManager() {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(h2DataSource());
em.setPackagesToScan(
new String[] { "com.baeldung.multipledb.model.user" });
HibernateJpaVendorAdapter vendorAdapter
= new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto",
env.getProperty("hibernate.hbm2ddl.auto"));
properties.put("hibernate.dialect",
env.getProperty("hibernate.dialect"));
em.setJpaPropertyMap(properties);
return em;
}
#Bean
public DataSource h2DataSource() {
DriverManagerDataSource dataSource
= new DriverManagerDataSource();
dataSource.setDriverClassName(
env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("h2.jdbc.url"));
dataSource.setUsername(env.getProperty("jdbc.h2"));
dataSource.setPassword(env.getProperty("jdbc.pass"));
return dataSource;
}
#Bean
public PlatformTransactionManager h2TransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
h2EntityManager().getObject());
return transactionManager;
}
**My test class :
**
#ActiveProfile("test")
#SpringBootTest
#Transactional
#DirtiesContext(methodMode = MethodMode.AFTER_METHOD)
public class UserRepositoryTests {
#Autowired
#Qualifier("h2EntityManager")
private EntityManger manager;
#UserRepository
private UserRepository userRepo;
// my tests
}
I thought that by specifying a profile, it would work but my tests don't pass since it tries to use my user DB.
I also tried setting the value in my application-test.properties but with no success.
spring.main.allow-bean-definition-overriding=true

How to set initial connections of a dynamic data source

I have a multi-tenant application with multiple datasources. The exact url which its connecting is set by runtime, depending on a request parameter. When I make a request at default 10 database-connections are created. With multiple datasources this fast sums up to a lot of connections. So I want to lower that number and also close the connections after a certain time.
My Configuration Class:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
basePackages = "com.example.demo",
entityManagerFactoryRef = "multiEntityManager",
transactionManagerRef = "multiTransactionManager"
)
public class PersistenceConfiguration extends WebMvcConfigurerAdapter {
private final String PACKAGE_SCAN = "com.example.demo";
//datasources
#Primary
#Bean(name = "COMP1")
public DataSource company1DS() {
return DataSourceBuilder.create()
.username("root")
.password("password")
.url("jdbc:mysql://81.123.456.789:3306/company1")
.build();
}
#Bean(name = "COMP2")
public DataSource company2DS() {
return DataSourceBuilder.create()
.username("root")
.password("password")
.url("jdbc:mysql://81.123.456.789:3306/company2")
.build();
}
#Bean(name = "multiRoutingDataSource")
public DataSource multiRoutingDataSource() {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("COMP1", company1DS());
targetDataSources.put("COMP2", company2DS());
MultiRoutingDataSource multiRoutingDataSource = new MultiRoutingDataSource();
multiRoutingDataSource.setDefaultTargetDataSource(company1DS());
multiRoutingDataSource.setTargetDataSources(targetDataSources);
return multiRoutingDataSource;
}
#Bean(name = "multiEntityManager")
public LocalContainerEntityManagerFactoryBean multiEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(multiRoutingDataSource());
em.setPackagesToScan(PACKAGE_SCAN);
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(hibernateProperties());
return em;
}
#Bean(name = "multiTransactionManager")
public PlatformTransactionManager multiTransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
multiEntityManager().getObject());
return transactionManager;
}
#Primary
#Bean(name = "dbSessionFactory")
public LocalSessionFactoryBean dbSessionFactory() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(multiRoutingDataSource());
sessionFactoryBean.setPackagesToScan(PACKAGE_SCAN);
sessionFactoryBean.setHibernateProperties(hibernateProperties());
return sessionFactoryBean;
}
private Properties hibernateProperties() {
Properties properties = new Properties();
return properties;
}
}
What I already tried:
I tried to change the values in the application.properties file like so:
spring.datasource.maxActive=2
spring.datasource.minIdle=2
spring.datasource.maxIdle=5
spring.datasource.initialSize=2
I tried to change the properties the dynamic way (PersistenceConfiguration.hibernateProperties()):
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("spring.datasource.maxActive",2);
properties.put("spring.datasource.minIdle",2);
properties.put("spring.datasource.maxIdle",5);
properties.put("spring.datasource.initialSize",2);
return properties;
}
But it seems that no properties get applied. When I show SHOW GLOBAL STATUS LIKE 'Connections'; in the MySQL workbench, I always get 10 more connections after I made a request from a new datasource.
If there is any important information missing, please let me know and I will add it.
I really appreciate your effort,
Greetings Alexander
EDIT
Since spring.datasource.max-active=2 is not valid, I also tried all the following in application-properties, as well as in the hibernateProperties();
spring.datasource.hikari.maximum-pool-size=2
spring.datasource.tomcat.initial-size=2
spring.datasource.tomcat.max-idle=2
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
properties.put("spring.datasource.hikari.maximum-pool-size",2);
properties.put("spring.datasource.tomcat.initial-size",2);
properties.put("spring.datasource.tomcat.max-idle",2);
properties.setProperty("spring.datasource.hikari.maximum-pool-size","2");
properties.setProperty("spring.datasource.tomcat.initial-size","2");
properties.setProperty("spring.datasource.tomcat.max-idle","2");
return properties;
}
Nothing changed a thing

Spring boot Single entity to multiple database

Is it possible to save single entity to multiple Databse (DB1 and DB2) by spring boot.For example am having two MYSQL DB with same table while posting data i need to save the person details into two dbs at same .?or any other way doing spring .Already i created two db Connections if the entity are different means, I can save the data, but the entity are same means i cant able to do?
public class Person {
private Long id;
private String name;
private String city;
}
My tablesCREATE TABLEperson(
idBIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
nameVARCHAR(255) DEFAULT NULL,
cityVARCHAR(255) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=INNODB DEFAULT CHARSET=latin1
For two DBS Named as DB1 and DB2
MY Connection Config is
#Configuration
#EnableJpaRepositories(basePackages =
{"com.onlinetutorialspoint.repository.db1"},
entityManagerFactoryRef = "db1EntityManager",
transactionManagerRef = "db1TransactionManager")
public class DB1_DataSource {
#Autowired
private Environment env;
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean db1EntityManager() {
LocalContainerEntityManagerFactoryBean em = new
LocalContainerEntityManagerFactoryBean();
em.setDataSource(db1Datasource());
em.setPackagesToScan(new String[]
{"com.onlinetutorialspoint.model.db1"});
em.setPersistenceUnitName("db1EntityManager");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.dialect",
env.getProperty("hibernate.dialect"));
properties.put("hibernate.show-sql",
env.getProperty("jdbc.show-sql"));
em.setJpaPropertyMap(properties);
return em;
}
#Primary
#Bean
public DataSource db1Datasource() {
DriverManagerDataSource dataSource
= new DriverManagerDataSource();
dataSource.setDriverClassName(
env.getProperty("jdbc.driver-class-name"));
dataSource.setUrl(env.getProperty("db1.datasource.url"));
dataSource.setUsername(env.getProperty("db1.datasource.username"));
dataSource.setPassword(env.getProperty("db1.datasource.password"));
return dataSource;
}
#Primary
#Bean
public PlatformTransactionManager db1TransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
db1EntityManager().getObject());
return transactionManager;
}
}
For second DB
#Configuration
#EnableJpaRepositories(basePackages =
{"com.onlinetutorialspoint.repository.db2"},
entityManagerFactoryRef = "db2EntityManager",
transactionManagerRef = "db2TransactionManager")
public class DB2_DataSource {
#Autowired
private Environment env;
#Bean
public LocalContainerEntityManagerFactoryBean db2EntityManager() {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(db2Datasource());
em.setPackagesToScan(
new String[]{"com.onlinetutorialspoint.model.db2"});
em.setPersistenceUnitName("db2EntityManager");
HibernateJpaVendorAdapter vendorAdapter
= new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.dialect",
env.getProperty("hibernate.dialect"));
properties.put("hibernate.show-sql",
env.getProperty("jdbc.show-sql"));
em.setJpaPropertyMap(properties);
return em;
}
#Bean
public DataSource db2Datasource() {
DriverManagerDataSource dataSource
= new DriverManagerDataSource();
dataSource.setDriverClassName(
env.getProperty("jdbc.driver-class-name"));
dataSource.setUrl(env.getProperty("db2.datasource.url"));
dataSource.setUsername(env.getProperty("db2.datasource.username"));
dataSource.setPassword(env.getProperty("db2.datasource.password"));
return dataSource;
}
#Bean
public PlatformTransactionManager db2TransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
db2EntityManager().getObject());
return transactionManager;
}
}
My Rest Controller
#RestController
public class CustomerController {
#Autowired
private PersonRepository personRepositorydb1;
#Autowired
private PersonRepository personRepositorydb2;
#RequestMapping("/save")
public Person savePersonDetails()
public savePersonDetails(#RequestBody Person person ){
personRepositorydb1.savePerson(person);
return personRepositorydb2.savePerson(person);
}
}
If i call two repository means its getting error the model name is already impoted
My Repository is
import com.onlinetutorialspoint.model.db1.Person;
#Repository
public interface PersonRepository extends CrudRepository<Person, Long>{
}
import com.onlinetutorialspoint.model.db2.Person;
#Repository
public interface PersonRepository extends CrudRepository<Person, Long>{
}
Maybe you can use the same approach in this answer
Spring Data + JPA with multiple datasources but only one set of Repositories
Here there is an example on how to use AbstractRoutingDataSource
https://www.endpoint.com/blog/2016/11/16/connect-multiple-jpa-repositories-using

spring-boot application doesn't load fixtures into one of multiple data sources

I have some trouble loading data fixtures during start of my spring boot application (1.5.2.RELEASE). The application uses two different database connections, one to our customers postgresql database on which we do not have permissions to create, insert or update anything. The other database is a local embedded h2 database (file). I want to load some data during application start into that h2 database by using the spring boot database initialization phase as described here but the data is never inserted into the h2 database, it stays empty as I can see using squirrel-sql.
This is the configuration in my application.properties:
spring.datasource.abc.driver-class-name=org.postgresql.Driver
spring.datasource.abc.initialize=false
spring.datasource.abc.url=jdbc:postgresql://localhost:5432/abc
spring.datasource.abc.username=abc
spring.datasource.abc.password=abc
spring.datasource.def.driver-class-name=org.h2.Driver
spring.datasource.def.initialize=true
spring.datasource.def.url=jdbc:h2:./${path.prefix}def/def;DB_CLOSE_ON_EXIT=FALSE'
spring.datasource.def.data=classpath:/data-h2.sql
I configured spring boot to use two different databases like described in this stackoverflow post and it all works fine if I pre-insert data by hand into the h2 database.
Configuration of my postgresql datasource:
#Configuration
#EnableJpaRepositories(basePackages = "....abc", entityManagerFactoryRef = "entityManagerFactory", transactionManagerRef = "transactionManager")
public class AbcDatabaseConfig
{
#Primary
#Bean
#ConfigurationProperties(prefix = "spring.datasource.abc")
public DataSource dataSource()
{
return DataSourceBuilder.create().build();
}
#Primary
#Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory()
{
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan("....abc");
HashMap<String, Object> properties = new HashMap<String, Object>();
properties.put("hibernate.hbm2ddl-auto", "none");
properties.put("hibernate.ejb.entitymanager_factory_name", "entityManagerFactory");
em.setJpaPropertyMap(properties);
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
return em;
}
#Primary
#Bean(name = "transactionManager")
public JpaTransactionManager transactionManager(#Qualifier("entityManagerFactory") final EntityManagerFactory factory)
{
return new JpaTransactionManager(factory);
}
}
Configuration of h2-datasource:
#Configuration
#EnableJpaRepositories(basePackages = "....def", entityManagerFactoryRef = "defEntityManagerFactory", transactionManagerRef = "defTransactionManager")
public class InavetDatabaseConfig
{
#Bean
#ConfigurationProperties(prefix = "spring.datasource.def")
public DataSource defDataSource()
{
return DataSourceBuilder.create().build();
}
#Bean(name = "defEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean defEntityManagerFactory()
{
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(defDataSource());
em.setPackagesToScan("....def");
HashMap<String, Object> properties = new HashMap<String, Object>();
properties.put("hibernate.hbm2ddl.auto", "create");
properties.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
properties.put("hibernate.ejb.entitymanager_factory_name", "defEntityManagerFactory");
em.setJpaPropertyMap(properties);
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
return em;
}
#Bean(name = "defTransactionManager")
public JpaTransactionManager defTransactionManager(
#Qualifier("defEntityManagerFactory") final EntityManagerFactory factory)
{
return new JpaTransactionManager(factory);
}
}
I found out, that only the #Primary marked data sources load fixtures. My workaround for this behaviour is adding code like this to my application:
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
populator.setContinueOnError(true);
populator.addScript(new PathResource("src/main/resources/data-h2.sql"));
DataSource dataSource = (DataSource) cac.getBean("defDataSource");
DatabasePopulatorUtils.execute(populator, dataSource);
Where cac is the instance of ConfigurableApplicationContext you get as return value by of: SpringApplication.run(,);

Multiple data source and schema creation in Spring Boot

I'm using Spring Boot. I finally managed to setup two data sources, but now I'm facing another issue.
with two data sources in place spring.jpa.hibernate.ddl-auto=create seems to stop working in my spring boot application, only spring.jpa.generate-ddl=true do the job now
I can not manage to select the auto-creation strategy for each of the data sources. I would prefer to create the schema for data source one, and just use the created schema in second DB with data source two.
Any body have idea how to resolve any of these issues? Note I don't want to completely throw away the auto-config if possible. I don't even know yet, if hibernate is able to just initialize schema in one persistence unit.
application.properties
spring.datasource-internal.url=jdbc:hsqldb:mem:testdb
spring.datasource-internal.username=sa
spring.datasource-internal.password=sa
spring.datasource-internal.driver-class-name=org.hsqldb.jdbcDriver
spring.datasource-internal.jpa.database-platform=org.hibernate.dialect.HSQLDialect
spring.datasource-external.url=jdbc:hsqldb:mem:testexternal
spring.datasource-external.username=sa
spring.datasource-external.password=sa
spring.datasource-external.driver-class-name=org.hsqldb.jdbcDriver
spring.datasource-external.jpa.database-platform=org.hibernate.dialect.HSQLDialect
flyway.enabled=false
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
spring.jpa.generate-ddl=true
DBInternalConfig
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = "cz.data.internal",
entityManagerFactoryRef = "internalEntityManagerFactory",
transactionManagerRef = "internalTransactionManager")
public class DBConfigInternal {
public static final String INTERNAL = "internal";
#Bean(name = "internalDataSource")
#Primary
#ConfigurationProperties(prefix = "spring.datasource-internal")
public DataSource internalDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "internalEntityManagerFactory")
#Primary
public LocalContainerEntityManagerFactoryBean internalEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
return builder
.dataSource(internalDataSource())
.packages("cz.data.internal.entity")
.persistenceUnit(INTERNAL)
.build();
}
#Bean(name = "internalTransactionManager")
#Primary
public PlatformTransactionManager internalTransactionManager() {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setDataSource(internalDataSource());
jpaTransactionManager.setPersistenceUnitName(INTERNAL);
return jpaTransactionManager;
}
}
DBExternalConfig
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
basePackages = "cz.data.external",
entityManagerFactoryRef = "externalEntityManagerFactory",
transactionManagerRef = "externalTransactionManager")
public class DBConfigExternal {
public static final String EXTERNAL = "external";
#Bean(name = "externalDataSource")
#ConfigurationProperties(prefix = "spring.datasource-external")
public DataSource externalDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "externalEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean externalEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
return builder
.dataSource(externalDataSource())
.packages("cz.data.external.entity")
.persistenceUnit(EXTERNAL)
.build();
}
#Bean(name = "externalTransactionManager")
public PlatformTransactionManager externalTransactionManager() {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setDataSource(externalDataSource());
jpaTransactionManager.setPersistenceUnitName(EXTERNAL);
return jpaTransactionManager;
}
}
M.W.
spring.jpa.hibernate.ddl-auto=create has stopped working, not because you have two DataSources, but because your application's creating its own LocalContainerEntityManagerFactoryBeans. This has the effect of disabling the auto-configuration of a LocalContainerEntityManagerFactoryBean so you now have to configure it yourself.
You can configure the two entity managers to have different schema generation behaviour like this (the first's doing update, the second's doing create):
#Bean(name = "externalEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean externalEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("hibernate.hbm2ddl.auto", "update");
return builder
.dataSource(externalDataSource())
.packages("cz.data.external.entity")
.persistenceUnit(EXTERNAL)
.properties(properties)
.build();
}
#Bean(name = "internalEntityManagerFactory")
#Primary
public LocalContainerEntityManagerFactoryBean internalEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("hibernate.hbm2ddl.auto", "create");
return builder
.dataSource(internalDataSource())
.packages("cz.data.internal.entity")
.persistenceUnit(INTERNAL)
.properties(properties)
.build();
}

Resources