I try to connect JpaRepository to work with Hibernate.
But I cannot autowire it like this.
I see error: Could not autowire field JpaUserRepository.
#Autowired
private JpaUserRepository jpaUserRepository;
My Repository:
public interface JpaUserRepository extends JpaRepository<User, Integer> {
}
What I missed?
My HibernateConfig:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = "com.springapp.mvc.repositories")
public class HibernateConfig {
#Bean
public DriverManagerDataSource dataSource(){
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setDriverClassName("org.postgresql.Driver");
driverManagerDataSource.setUrl("jdbc:postgresql://localhost:5432");
driverManagerDataSource.setUsername("postgres");
driverManagerDataSource.setPassword("password");
return driverManagerDataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource());
factoryBean.setPersistenceUnitName("jpaData");
factoryBean.setJpaVendorAdapter(hibernateJpaVendorAdapter());
Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
properties.put("hibernate.show_sql", "true");
properties.put("hibernate.format_sql", "true");
properties.put("hibernate.hbm2ddl.auto", "update");
factoryBean.setJpaProperties(properties);
factoryBean.setPackagesToScan(new String[]{"com.springapp.mvc.models"});
return factoryBean;
}
#Bean
public JpaTransactionManager transactionManager(){
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return jpaTransactionManager;
}
#Bean
public HibernateJpaVendorAdapter hibernateJpaVendorAdapter(){
return new HibernateJpaVendorAdapter();
}
}
I found solution myself. I upgraded spring to version 4.1.7 and it works.
Related
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;
}
....
This question already has an answer here:
JpaRepository won't save data
(1 answer)
Closed 2 years ago.
I have a problem creating a Spring project using Spring Data JPA and Hibernate. When I called save method on the repository, it didn't insert my object to the database.
Hibernate config class:
#Configuration
#EnableTransactionManagement
#ComponentScan({ "com.app.config" })
#PropertySource(value = { "classpath:application.properties" })
#EnableJpaRepositories(basePackages = { "com.app.repository" })
public class HibernateConfiguration {
#Autowired
private Environment environment;
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "com.app.model", "com.app.repository" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan(new String[] { "com.app.model", "com.app.repository" });
factory.setDataSource(dataSource());
factory.setJpaProperties(hibernateProperties());
factory.afterPropertiesSet();
return factory.getObject();
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
return dataSource;
}
#Bean
#Autowired
public HibernateTemplate getHibernateTemplate(SessionFactory sessionFactory) {
HibernateTemplate hibernateTemplate = new HibernateTemplate(sessionFactory);
return hibernateTemplate;
}
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
properties.put("hibernate.hbm2ddl.auto", environment.getRequiredProperty("hibernate.hbm2ddl.auto"));
return properties;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory s) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(s);
return txManager;
}
#Bean
#Autowired
public EntityManager entityManager(EntityManagerFactory entityManagerFactory) {
return entityManagerFactory.createEntityManager();
}
}
Repository class:
#Repository
public interface CityRepository extends BaseRepository<City, Integer> {
City findByName(String name);
List<City> findAll();
#Query("SELECT c.name FROM City c")
List<String> findAllCityName();
}
Service class:
#Service
public class CityService {
#Autowired
private CityRepository cityRepository;
public void saveCity(City city) {
return cityRepository.save(city);
}
}
BaseRepository is extended by CrudRepository in Spring JPA.
The code above runs without any errors but entity was not saved to the DB. Does anyone know what the issue with my code is?
I've resolved my problem by follow answer from JB Nizet above.
Drop the sessionFactory, drop the hibernateTemplate, replace the HibernateTransactionManager by a JpaTransactionManager. – JB Nizet
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.
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));
}
}
I want to use 2 hibernate db connections. I am facing this error, i tries to solved if but could not find a way. I have made two different configuration files and annotated #bean and #qualifires but it still dosent work.
Error
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'transactionManager' defined in class path resource [com/project/configuration/RepositoryConfiguration.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [org.hibernate.SessionFactory]: : No qualifying bean of type [org.hibernate.SessionFactory] is defined: expected single matching bean but found 2: sessionFactory2,sessionFactory; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.hibernate.SessionFactory] is defined: expected single matching bean but found 2: sessionFactory2,sessionFactory
My configurations :
#Configuration
#EnableTransactionManagement
#PropertySource({ "classpath:hibernate.properties" })
public class RepositoryConfig2 {
#Autowired
private Environment environment;
#Bean(name="sessionFactory2")
public LocalSessionFactoryBean sessionFactory2() {
LocalSessionFactoryBean sessionFactory2 = new LocalSessionFactoryBean();
sessionFactory2.setDataSource(dataSource2());
sessionFactory2.setHibernateProperties(hibernateProperties());
sessionFactory2.setPackagesToScan(new String[] { "com.project" });
return sessionFactory2;
}
#Bean
public Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect2"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql2"));
properties.put("hibernate.hbm2ddl.auto", "update");// environment.getRequiredProperty("hibernate.hbm2ddl.auto")
return properties;
}
#Bean(name = "datasource2")
public DataSource dataSource2() {
DriverManagerDataSource dataSource2 = new DriverManagerDataSource();
dataSource2.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName2"));
dataSource2.setUrl(environment.getRequiredProperty("jdbc.url2"));
dataSource2.setUsername(environment.getRequiredProperty("jdbc.username2"));
dataSource2.setPassword(environment.getRequiredProperty("jdbc.password2"));
return dataSource2;
}
#Autowired
#Qualifier(value = "sessionFactory2")
public HibernateTransactionManager transactionManager(SessionFactory s) {
HibernateTransactionManager txManager2 = new HibernateTransactionManager();
txManager2.setSessionFactory(s);
return txManager2;
}
}
Second Configuration :
#Configuration
#EnableTransactionManagement
#PropertySource({ "classpath:hibernate.properties" })
public class RepositoryConfiguration {
#Autowired
private Environment environment;
#Bean(name="sessionFactory")
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setHibernateProperties(hibernateProperties());
sessionFactory.setPackagesToScan(new String[] { "com.project" });
return sessionFactory;
}
#Bean
public Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.hbm2ddl.auto", "update");// environment.getRequiredProperty("hibernate.hbm2ddl.auto")
return properties;
}
#Bean(name = "datasource")
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
return dataSource;
}
#Bean
#Autowired
#Qualifier(value = "sessionFactory")
public HibernateTransactionManager transactionManager(SessionFactory s) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(s);
return txManager;
}
}
Ok so, I did more R&D and with luck i solved the problem..
So here's what i did
Merged my RepositoryConfiguration into one class.
Removed Autowired from HibernateTransactionManager and manually wired sessionFactories.
Also cjanged packages to scan for hibernate(realized it will create same tables in both databases)
Add qualifier in #Transactional(import from spring.)
#Transactional("sessionFactoryTransactionManager")
in my repositories.
#Configuration
#EnableTransactionManagement
#PropertySource({ "classpath:hibernate.properties" })
public class RepositoryConfiguration {
#Autowired
private Environment environment;
#Bean(name = "sessionFactory")
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setHibernateProperties(hibernateProperties());
sessionFactory.setPackagesToScan(new String[] { "com.project" });
return sessionFactory;
}
#Bean
public Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.hbm2ddl.auto", "update");// environment.getRequiredProperty("hibernate.hbm2ddl.auto")
return properties;
}
#Bean(name = "sessionFactory2")
public LocalSessionFactoryBean sessionFactory2() {
LocalSessionFactoryBean sessionFactory2 = new LocalSessionFactoryBean();
sessionFactory2.setDataSource(dataSource());
sessionFactory2.setHibernateProperties(hibernateProperties2());
sessionFactory2.setPackagesToScan(new String[] { "com.server" });
return sessionFactory2;
}
#Bean
public Properties hibernateProperties2() {
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect2"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql2"));
properties.put("hibernate.hbm2ddl.auto", "update2");// environment.getRequiredProperty("hibernate.hbm2ddl.auto")
return properties;
}
#Bean(name = "datasource2")
public DataSource dataSource2() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName2"));
dataSource.setUrl(environment.getRequiredProperty("jdbc.url2"));
dataSource.setUsername(environment.getRequiredProperty("jdbc.username2"));
dataSource.setPassword(environment.getRequiredProperty("jdbc.password2"));
return dataSource;
}
#Bean(name = "datasource")
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
return dataSource;
}
#Autowired
#Qualifier("sessionFactory")
private SessionFactory sessionFactory;
#Autowired
#Qualifier("sessionFactory2")
private SessionFactory sessionFactory2;
#Bean(name = "sessionFactoryTransactionManager")
public HibernateTransactionManager transactionManager() {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(this.sessionFactory);
return txManager;
}
#Bean(name = "sessionFactory2TransactionManager")
public HibernateTransactionManager transactionManager2() {
HibernateTransactionManager txManager2 = new HibernateTransactionManager();
txManager2.setSessionFactory(this.sessionFactory2);
return txManager2;
}
}