I have to connect to two databases (PostgreSQL , Oracle) which contains same tables.
When I create entities of same tables in different packages it doesn't work.
Even though using two database connections the application always points to one database connection only.
Is it possible in Hibernate to connect to same tables from different databases?
application.properties
#DataSource settings for Postgres
datasource.secondary.url =jdbc:postgresql://localhost:5433/****
datasource.secondary.username =postgres
datasource.secondary.password =Postgre#1234
datasource.secondary.driverClassName=org.postgresql.Driver
datasource.secondary.dialect=org.hibernate.dialect.PostgreSQLDialect
#DataSource settings for oracle
datasource.primary.url = jdbc:oracle:thin:#localhost:1521:xe
datasource.primary.username = ***
datasource.primary.password = ***
datasource.primary.driverClassName=oracle.jdbc.OracleDriver
Configuration
#Configuration
public class MultipleDBConfig {
#Primary
#Bean(name = "oracleDb")
#ConfigurationProperties(prefix = "datasource.primary")
public DataSource mysqlDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "postgresDb")
#ConfigurationProperties(prefix = "datasource.secondary")
public DataSource postgresDataSource() {
return DataSourceBuilder.create().build();
}
}
Primary
#Configuration
#EnableJpaRepositories(
entityManagerFactoryRef = "primaryEntityManager",
transactionManagerRef = "primaryEntityManagerFactory",
basePackages = {"com.ubl.model.*"})
public class PrimaryDBConfig {
#Bean(name = "primaryEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] {"com.ubl.model.migration.entity.oracle"});
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalJpaProperties());
em.setPersistenceUnitName("customers");
return em;
}
Properties additionalJpaProperties(){
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "update");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.OracleDialect");
properties.setProperty("hibernate.show_sql", "true");
return properties;
}
#Bean
public DataSource dataSource(){
return DataSourceBuilder.create()
.url("jdbc:oracle:thin:#localhost:1521:xe")
.driverClassName("oracle.jdbc.OracleDriver")
.username("****")
.password("****")
.build();
}
#Bean(name = "primarytransactionManager")
public JpaTransactionManager transactionManager(EntityManagerFactory customerEntityManager){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(customerEntityManager);
return transactionManager;
}
}
Secondary
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "secondaryEntityManagerFactory",
transactionManagerRef = "secondaryTransactionManager",
basePackages = {"com.ubl.*"})
public class SecondaryDBConfig {
#Autowired
JpaVendorAdapter jpaVendorAdapter;
#Value("${datasource.secondary.url}")
private String databaseURL;
#Value("${datasource.secondary.username}")
private String username;
#Value("${datasource.secondary.password}")
private String password;
#Value("${datasource.secondary.driverClassName}")
private String driverClassName;
#Value("${datasource.secondary.dialect}")
private String dialect;
public SecondaryDBConfig() {
System.out.println("Secondary repository");
System.out.println("driverClassName: *************" +driverClassName);
}
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource(databaseURL, username, password);
dataSource.setDriverClassName(driverClassName);
return dataSource;
}
#Bean(name = "secondaryEntityManager")
public EntityManager entityManager() {
return entityManagerFactory().createEntityManager();
}
#Bean(name = "secondaryEntityManagerFactory")
public EntityManagerFactory entityManagerFactory() {
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", dialect);
LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource());
emf.setJpaVendorAdapter(jpaVendorAdapter);
emf.setPackagesToScan("com.ubl.model.*"); // package for entities
emf.setPersistenceUnitName("secondaryPersistenceUnit");
emf.setJpaProperties(properties);
emf.afterPropertiesSet();
return emf.getObject();
}
#Bean(name = "secondaryTransactionManager")
public PlatformTransactionManager transactionManager() {
return new JpaTransactionManager(entityManagerFactory());
}
}
When I run the application I get below error:
Caused by: org.hibernate.tool.schema.extract.spi.SchemaExtractionException: More than one table found in namespace (, )
Your second config appears to use the same namespace as your first:
basePackages = {"com.ubl.model.*"}
basePackages = {"com.ubl.*"}
Once your second config looks for it's entities, it discovers the same as the fist does and thus resulting in the exception. You will want to separate your entities and both your configs.
basePackages = {"com.ubl.model.datasource1"}
basePackages = {"com.ubl.model.datasource2"} // well you get the idea and will find better names ;)
Then move all your entities in the respective folder. Although the table are "the same" you need one #Entity-Class for each individual Table, even though the tables you will want to use are structurally identical.
Related
I'm getting FooBar is not mapped exception, even though I have placed all the necessary annotations:
The Entity annotation in the model class:
model/FooBar.java*
#Data
#Entity
#Table(name = "ORDERS")
public class FooBar {}
The Repository, PersistenceContext and Transactioinal in DAO. Also, I referenced it by the name of the class, "FooBar", correctly
db/FooBarDao.java
#Repository
public class OrderDAO {
#PersistenceContext
private EntityManager em;
#Transactional
public List<FooBar> getFooBars() {
return em.createQuery(
"select fb from FooBar fb",
FooBar.class
).getResultList();
}
}
Here is the configuration to get it all working:
conf/DbConfig.java
#EnableTransactionManagement
#Configuration
#ComponentScan(basePackages = {"project.db"})
public class DbConfig {
#Autowired
public Environment env;
#Bean
public DataSource dataSource() {
System.out.println("Configuring database!!!!!!!!");
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("org.hsqldb.jdbcDriver");
ds.setUrl("jdbc:hsqldb:mem:myjdbc");
new JdbcTemplate(ds)
.update(FileUtil.readFile2("./src/main/java/project/db/sql/initialize.sql"));
return ds;
}
#Bean
public PlatformTransactionManager transactionManager(
EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
#Bean
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setPersistenceProviderClass(HibernatePersistenceProvider.class);
factory.setPackagesToScan("model");
factory.setDataSource(dataSource());
factory.setJpaProperties(additionalProperties());
factory.afterPropertiesSet();
return factory.getObject();
}
private Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "validate");
properties.setProperty("hibernate.dialect",
"org.hibernate.dialect.HSQLDialect");
properties.setProperty("hibernate.show_sql", "true");
properties.setProperty("hibernate.format_sql", "true");
return properties;
}
}
It's not finding the mapping, even though I have set the annotations correctly, and referenced the class correctly. So the problem is most likely with scanning for the model class.
My project structure is /src/main/java/project/...
So, scanning for model:
factory.setPackagesToScan("model");
Will not find any beans. Instead, I need to do
factory.setPackagesToScan("project.model");
Which fixes the problem.
I want to configure two datasource for my spring boot project, but I have same entities in the two databases, so I ask if it is possible to make the entities in one package and initialise the specific datasource in the repositories.
This my configuration :
#Configuration
#EnableAutoConfiguration
public class NwlConfiguration {
#Bean
#Primary
#ConfigurationProperties("spring.datasource")
public DataSourceProperties source1DataSourceProperties() {
return new DataSourceProperties();
}
#Bean(name = "source1")
#Primary
#ConfigurationProperties("spring.datasource")
public DataSource source1DataSource() {
return source1DataSourceProperties().initializeDataSourceBuilder().build();
}
#Bean
#ConfigurationProperties("source2.datasource")
public DataSourceProperties source2DataSourceProperties() {
return new DataSourceProperties();
}
#Bean(name = "source2")
#ConfigurationProperties("source2.datasource")
public DataSource source2DataSource() {
return source2DataSourceProperties().initializeDataSourceBuilder().build();
}
}
Your Configuration looks ok. Only thing is you need to assign which Configuration will be used for which Repository.
If there are multiple entities you can put them in a common package.
Like this
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "barEntityManagerFactory",
transactionManagerRef = "barTransactionManager", basePackages = {"com.foobar.bar.repo"})
public class BarDbConfig {
Complete Code
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "barEntityManagerFactory",
transactionManagerRef = "barTransactionManager", basePackages = {"com.foobar.bar.repo"})
public class BarDbConfig {
#Bean(name = "barDataSource")
#ConfigurationProperties(prefix = "bar.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "barEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean barEntityManagerFactory(
EntityManagerFactoryBuilder builder, #Qualifier("barDataSource") DataSource dataSource) {
return builder.dataSource(dataSource).packages("com.foobar.bar.domain").persistenceUnit("bar")
.build();
}
#Bean(name = "barTransactionManager")
public PlatformTransactionManager barTransactionManager(
#Qualifier("barEntityManagerFactory") EntityManagerFactory barEntityManagerFactory) {
return new JpaTransactionManager(barEntityManagerFactory);
}
}
2nd Datasource Config Class
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactory",
basePackages = {"com.foobar.foo.repo"})
public class FooDbConfig {
#Primary
#Bean(name = "dataSource")
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Primary
#Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
EntityManagerFactoryBuilder builder, #Qualifier("dataSource") DataSource dataSource) {
return builder.dataSource(dataSource).packages("com.foobar.foo.domain").persistenceUnit("foo")
.build();
}
#Primary
#Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager(
#Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
}
Refer this article for more Detail
I have a class with config. And I have a method entityManagerFactory() that tagged like Bean.
#Configuration
#EnableTransactionManagement
#PropertySource({ "classpath:hibernate.properties" })
#EnableJpaRepositories
public class PersistenceJPAConfig {
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] { "java.entities" });
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
#Bean
public DataSource dataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/carpark?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTCx`");
dataSource.setUsername( "root" );
dataSource.setPassword( "1111" );
return dataSource;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
return new PersistenceExceptionTranslationPostProcessor();
}
public Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "update");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
return properties;
}
}
And I have a service that use EntityManager. EntityManager tagged like #Autowired, and spring create EntityManager is null. Where I'm configured incorrectly. I need to entityManager with fields from method entityManagerFactory() (in class PersistenceJPAConfig).
#Service
public class BusService {
#Autowired
private BusRepository busRepository;
#Autowired
private EntityManager entityManager;
public void getBus(){
try{
entityManager.getTransaction().begin();
Query query = entityManager.createNativeQuery("SELECT ID, NUMBER , Rote_ID FROM bus", Bus.class);
busRepository.save(query.getResultList());
System.out.println(busRepository.toString());
}finally {
entityManager.getTransaction().commit();
}
}
}
my packages are located like this
thanks in advance
You should use the `#PersistenceContext' annotation to inject the entity manager:
#Service
public class BusService {
#Autowired
private BusRepository busRepository;
#PersistenceContext
private EntityManager entityManager;
public void getBus(){
try{
entityManager.getTransaction().begin();
Query query = entityManager.createNativeQuery("SELECT ID, NUMBER , Rote_ID FROM bus", Bus.class);
busRepository.save(query.getResultList());
System.out.println(busRepository.toString());
} finally {
entityManager.getTransaction().commit();
}
}
there are several reasons to do that, you can get an overview here
and update you configuration class with the #ComponentScan annotation
#Configuration
#EnableTransactionManagement
#PropertySource({ "classpath:hibernate.properties" })
#EnableJpaRepositories
#ComponentScan(basePackages = {
"model.service"})
public class PersistenceJPAConfig {
....
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() { LocalContainerEntityManagerFactoryBean em = new
LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] { "model.entities" });
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
....
I'm trying to configure two H2 datasource. I tried dozen of tutorials but it still does not works. Now I have two configuration classes
First, default configuration:
#Configuration
#EnableJpaRepositories(
basePackages = "com.yyy.xxx.repository",
entityManagerFactoryRef = "defaultEntityManagerFactory",
transactionManagerRef = "defaultTransactionManager")
#EnableTransactionManagement
public class DefaultJpaConfiguration {
private final JpaVendorAdapter jpaVendorAdapter;
public DefaultJpaConfiguration(JpaVendorAdapter jpaVendorAdapter) {
this.jpaVendorAdapter = jpaVendorAdapter;
}
#Bean(name = "defaultDataSource")
#ConfigurationProperties(prefix = "datasource.default")
public DataSource defaultDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "defaultEntityManagerFactory")
public EntityManagerFactory defaultEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(defaultDataSource());
lef.setJpaVendorAdapter(jpaVendorAdapter);
lef.setPackagesToScan("com.yyy.xxx.entity");
lef.setPersistenceUnitName("defaultPersistenceUnit");
lef.afterPropertiesSet();
return lef.getObject();
}
#Bean(name = "defaultTransactionManager")
public PlatformTransactionManager defaultTransactionManager() {
return new JpaTransactionManager(defaultEntityManagerFactory());
}
#Bean(name = "defaultEntityManager")
public EntityManager defaultEntityManager() {
return defaultEntityManagerFactory().createEntityManager();
}
}
And the second one:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
basePackages = "com.yyy.xxx.adminPassword.repository",
entityManagerFactoryRef = "passwordEntityManagerFactory",
transactionManagerRef = "passwordTransactionManager")
public class PlkPasswordsDatabaseConfiguration {
private final JpaVendorAdapter jpaVendorAdapter;
public PlkPasswordsDatabaseConfiguration(JpaVendorAdapter jpaVendorAdapter) {
this.jpaVendorAdapter = jpaVendorAdapter;
}
#Bean(name = "passwordDataSource")
#ConfigurationProperties(prefix = "datasource.adminPasswords")
public DataSource passwordDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "passwordEntityManagerFactory")
public EntityManagerFactory passwordEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(passwordDataSource());
lef.setJpaVendorAdapter(jpaVendorAdapter);
lef.setPackagesToScan("com.yyy.xxx.adminPassword.entity");
lef.setPersistenceUnitName("passwordPersistenceUnit");
lef.afterPropertiesSet();
return lef.getObject();
}
#Bean(name = "passwordEntityManager")
public EntityManager passwordEntityManager() {
return passwordEntityManagerFactory().createEntityManager();
}
#Bean(name = "passwordTransactionManager")
public PlatformTransactionManager passwordTransactionManager() {
return new JpaTransactionManager(passwordEntityManagerFactory());
}
}
Properties file:
datasource.default.url=jdbc:h2:mem:xxx_db;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false
datasource.default.username=sa
datasource.default.password=
datasource.adminPasswords.url=jdbc:h2:mem:xxx_plk_passwords_db;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false
datasource.adminPasswords.username=sa
datasource.adminPasswords.password=
The error I got say:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
But as you can see in configuration classes entityManagerFactoryRef is set.
when you have multiple datasources, EntityManager and PlatformTransactionManager, spring expects you to specify which one of it is the primary one. Add #Primary on one of the datasource, entitymanager and transactionmanager(doesn't matter which) bean
i am developing web application which uses multitenant database configuration.
I want to add tenant dynamically.
I added master controller to create master schema which hold tenant record created dynamically.
but problem is when i request to create tenant it went to MultitenantConnectionProvider i created database there but in database i want to scan package com.appointment.schedular.model.tenant and create table in ne database as well.
Source code
MasterDatabaseConfig.java
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
basePackages = "com.appointment.schedular.dao.master",
entityManagerFactoryRef = "masterEntityManager",
transactionManagerRef = "masterTransactionManager"
)
#PropertySource("classpath:application.properties")
public class MasterDatabaseConfig {
#Autowired
private Environment springEnvironment;
#Bean(name="masterDataSource")
public DataSource masterDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(springEnvironment.getProperty("master.datasource.classname"));
dataSource.setUrl(springEnvironment.getProperty("master.datasource.url") + "?createDatabaseIfNotExist=true");
dataSource.setUsername(springEnvironment.getProperty("master.datasource.user"));
dataSource.setPassword(springEnvironment.getProperty("master.datasource.password"));
return dataSource;
}
#Bean(name = "masterEntityManager")
#Primary
public LocalContainerEntityManagerFactoryBean masterEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean
= new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(masterDataSource());
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
entityManagerFactoryBean.setPackagesToScan(new String[]{"com.appointment.schedular.model.master"});
entityManagerFactoryBean.setJpaProperties(getHibernateProperties());
entityManagerFactoryBean.setPersistenceUnitName("master");
return entityManagerFactoryBean;
}
private Properties getHibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", springEnvironment.getProperty("hibernate.dialect","org.hibernate.dialect.MySQLDialect"));
properties.put("hibernate.show_sql", springEnvironment.getProperty("hibernate.show_sql", "true"));
properties.put("hibernate.format_sql", springEnvironment.getProperty("hibernate.format_sql", "true"));
properties.put("hibernate.hbm2ddl.auto", springEnvironment.getProperty("hibernate.hbm2ddl.auto", "update"));
return properties;
}
#Bean(name = "masterTransactionManager")
public JpaTransactionManager transactionManager(EntityManagerFactory masterEntityManager) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(masterEntityManager);
return transactionManager;
}
}
TenantDatabaseConfig.java
#Configuration
#EnableTransactionManagement
#ComponentScan("com.appointment.schedular.tenant")
#EnableJpaRepositories(
entityManagerFactoryRef = "tenantEntityManager",
transactionManagerRef = "tenantTransactionManager",
basePackages = {"com.appointment.schedular.dao.tenant"})
#PropertySource("classpath:application.properties")
public class TenantDatabaseConfig {
#Autowired
private Environment springEnvironment;
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
return new HibernateJpaVendorAdapter();
}
#Bean(name = "tenantDataSource")
public DataSource tenantDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(springEnvironment.getProperty("tenant.datasource.classname"));
dataSource.setUrl(springEnvironment.getProperty("tenant.datasource.url")+"xy" + "?createDatabaseIfNotExist=true");
dataSource.setUsername(springEnvironment.getProperty("tenant.datasource.user"));
dataSource.setPassword(springEnvironment.getProperty("tenant.datasource.password"));
return dataSource;
}
#Bean(name = "tenantEntityManager")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
MultiTenantConnectionProvider connectionProvider,
CurrentTenantIdentifierResolver tenantResolver) {
LocalContainerEntityManagerFactoryBean emfBean = new LocalContainerEntityManagerFactoryBean();
emfBean.setDataSource(tenantDataSource());
emfBean.setPackagesToScan("com.appointment.schedular.model.tenant");
emfBean.setJpaVendorAdapter(jpaVendorAdapter());
Map<String, Object> properties = new HashMap<>();
properties.put(org.hibernate.cfg.Environment.MULTI_TENANT, MultiTenancyStrategy.SCHEMA);
properties.put(org.hibernate.cfg.Environment.MULTI_TENANT_CONNECTION_PROVIDER, connectionProvider);
properties.put(org.hibernate.cfg.Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, tenantResolver);
properties.put("hibernate.ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy");
properties.put("hibernate.dialect", springEnvironment.getProperty("hibernate.dialect"
, "org.hibernate.dialect.MySQLDialect"));
properties.put("hibernate.show_sql", springEnvironment.getProperty("hibernate.show_sql"
, "true"));
properties.put("hibernate.format_sql", springEnvironment.getProperty("hibernate.format_sql"
, "true"));
properties.put("hibernate.hbm2ddl.auto", springEnvironment.getProperty("hibernate.hbm2ddl.auto"
, "update"));
emfBean.setJpaPropertyMap(properties);
emfBean.setPersistenceUnitName("master");
return emfBean;
}
#Bean(name = "tenantTransactionManager")
public JpaTransactionManager transactionManager(EntityManagerFactory tenantEntityManager) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(tenantEntityManager);
return transactionManager;
}
}
MultitenantConnectionProviderImpl.java
#SuppressWarnings("serial")
#Component
#PropertySource("classpath:application.properties")
public class MultiTenantConnectionProviderImpl extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl implements ApplicationListener<ContextRefreshedEvent> {
#Autowired
private Environment springEnvironment;
#Autowired
private TenantDao tenantDao;
#Autowired
#Qualifier("tenantDataSource")
DataSource masterDataSource;
/*#Autowired
#Qualifier("tenantEntityManager")
EntityManager*/
private final Map<String, DataSource> map = new HashMap<>();
#Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
init();
}
private void init() {
List<Tenant> tenants = tenantDao.findAll();
for (Tenant tenant : tenants) {
DataSource genDatasource = constructDataSource(tenant.getTenantKey());
map.put(tenant.getTenantKey(), genDatasource);
/*
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean
= new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(genDatasource);
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
entityManagerFactoryBean.setPackagesToScan(new String[]{"com.appointment.schedular.model.tenant"});
Map<String, Object> properties = new HashMap<>();
properties.put("hibernate.ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy");
properties.put("hibernate.dialect", springEnvironment.getProperty("hibernate.dialect"
, "org.hibernate.dialect.MySQLDialect"));
properties.put("hibernate.show_sql", springEnvironment.getProperty("hibernate.show_sql"
, "true"));
properties.put("hibernate.format_sql", springEnvironment.getProperty("hibernate.format_sql"
, "true"));
properties.put("hibernate.hbm2ddl.auto", springEnvironment.getProperty("hibernate.hbm2ddl.auto"
, "update"));
entityManagerFactoryBean.setJpaPropertyMap(properties);
*/
}
}
private DataSource constructDataSource(String dbName) {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(springEnvironment.getProperty("tenant.datasource.classname"));
dataSource.setUrl(springEnvironment.getProperty("tenant.datasource.url") + dbName+ "?createDatabaseIfNotExist=true");
dataSource.setUsername(springEnvironment.getProperty("tenant.datasource.user"));
dataSource.setPassword(springEnvironment.getProperty("tenant.datasource.password"));
try {
dataSource.getConnection().createStatement().execute("CREATE DATABASE IF NOT EXISTS " + dbName);
} catch (Exception ex) {
System.out.println(ex);
}
return dataSource;
}
#Override
protected DataSource selectAnyDataSource() {
return masterDataSource;
}
#Override
protected DataSource selectDataSource(String key) {
return map.get(key);
}
public void addTenant(String tenantKey) {
map.put(tenantKey, constructDataSource(tenantKey));
}
}
TenantController.java
#Controller
#RequestMapping("/tenant")
public class TenantController {
#Autowired
TenantDao tenantRepo;
#Autowired
MultiTenantConnectionProviderImpl multiTenantConnectionProviderImpl;
#SuppressWarnings("rawtypes")
#CrossOrigin
#RequestMapping(value = "/",
method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody String registerTenant(#RequestBody Map map) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Tenant tenant = mapper.convertValue(map, Tenant.class);
String tenantKey = tenant.getName().replaceAll("[^a-zA-Z]+", "").toLowerCase().trim();
Optional<Tenant> previouslyStored = tenantRepo.findByTenantKey(tenantKey);
String response="Sorry your company name ("+tenant.getName()+")"+" is already taken";
if (!previouslyStored.isPresent()) {
tenant.setTenantKey(tenantKey);
tenantRepo.save(tenant);
multiTenantConnectionProviderImpl.addTenant(tenantKey);
response = "Successfully registered, your key is " + tenantKey;
return response;
}
return new ObjectMapper().writeValueAsString(response);
}
}
Replace your MultitenantConnectionProviderImpl.java with this code. Use inject service for creating your tables using configuration class.
#SuppressWarnings("serial")
#Component
#PropertySource("classpath:application.properties")
public class MultiTenantConnectionProviderImpl extends AbstractDataSourceBasedMultiTenantConnectionProviderImpl implements ApplicationListener<ContextRefreshedEvent>,ServiceRegistryAwareService {
#Autowired
private Environment springEnvironment;
#Autowired
private TenantDao tenantDao;
#Autowired
#Qualifier("dataSource1")
DataSource masterDataSource;
#Autowired
MultiTenantConnectionProvider connectionProvider;
#Autowired
CurrentTenantIdentifierResolver tenantResolver;
#Autowired
TenantDatabaseConfig tenantDatabaseConfig;
private final Map<String, DataSource> map = new HashMap<>();
#Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
init();
}
private void init() {
List<Tenant> tenants = tenantDao.findAll();
for (Tenant tenant : tenants) {
map.put(tenant.getTenantKey(), constructDataSource(tenant.getTenantKey()));
}
}
private DataSource constructDataSource(String dbName) {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(springEnvironment.getProperty("tenant.datasource.classname"));
dataSource.setUrl(springEnvironment.getProperty("tenant.datasource.url") + dbName+"?createDatabaseIfNotExist=true");
dataSource.setUsername(springEnvironment.getProperty("tenant.datasource.user"));
dataSource.setPassword(springEnvironment.getProperty("tenant.datasource.password"));
entityManagerFactory(dataSource,connectionProvider, tenantResolver);
return dataSource;
}
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource,
MultiTenantConnectionProvider connectionProvider,
CurrentTenantIdentifierResolver tenantResolver) {
LocalContainerEntityManagerFactoryBean emfBean = new LocalContainerEntityManagerFactoryBean();
emfBean.setDataSource(dataSource);
emfBean.setPackagesToScan("com.appointment.schedular.model.tenant");
emfBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
emfBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
Map<String, Object> properties = new HashMap<>();
properties.put(org.hibernate.cfg.Environment.MULTI_TENANT, MultiTenancyStrategy.DATABASE);
properties.put(org.hibernate.cfg.Environment.MULTI_TENANT_CONNECTION_PROVIDER, connectionProvider);
properties.put(org.hibernate.cfg.Environment.MULTI_TENANT_IDENTIFIER_RESOLVER, tenantResolver);
properties.put("hibernate.ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy");
properties.put("hibernate.dialect", springEnvironment.getProperty("hibernate.dialect"
, "org.hibernate.dialect.MySQLDialect"));
properties.put("hibernate.show_sql", springEnvironment.getProperty("hibernate.show_sql"
, "true"));
properties.put("hibernate.format_sql", springEnvironment.getProperty("hibernate.format_sql"
, "true"));
properties.put("hibernate.hbm2ddl.auto", springEnvironment.getProperty("hibernate.hbm2ddl.auto"
, "update"));
emfBean.setJpaPropertyMap(properties);
emfBean.setPersistenceUnitName(dataSource.toString());
emfBean.afterPropertiesSet();
//emfBean.setEntityManagerFactoryInterface((EntityMana)emfBean);
//emfBean.setBeanName("srgsrohtak");
return emfBean;
}
public JpaTransactionManager transactionManager(EntityManagerFactory tenantEntityManager) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(tenantEntityManager);
transactionManager.afterPropertiesSet();
return transactionManager;
}
#Override
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
Map lSettings = serviceRegistry.getService(ConfigurationService.class).getSettings();
DataSource localDs = (DataSource) lSettings.get("hibernate.connection.datasource");
masterDataSource = localDs;
}
#Override
protected DataSource selectAnyDataSource() {
return masterDataSource;
}
#Override
protected DataSource selectDataSource(String key) {
return map.get(key);
}
public void addTenant(String tenantKey) {
map.put(tenantKey, constructDataSource(tenantKey));
}
}