In my Spring Java Config file,i use AbstractRoutingDatasource successfully to switch multiple databases connections.
public MyRoutingDataSource myRoutingDataSource() {
MyRoutingDataSource dataSource = new MyRoutingDataSource();
Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
dataSource.setDefaultTargetDataSource(defaultDataSource());
dataSource.setTargetDataSources(targetDataSources);
return dataSource;
}
But when i want specific SQL requests that differs from datasources PostgreSQL/Oracle etc.. (like pagination limit/rowNums), i have to associated a specific hibernate dialect.
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(false);
vendorAdapter.setShowSql(true);
vendorAdapter.setDatabasePlatform("org.hibernate.dialect.PostgreSQL81Dialect");
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("fr.appli.model");
factory.setDataSource(myRoutingDataSource());
My question is how can i change hibernate dialect in my EntityManager, when i change datasource from with AbstractRoutingDatasource ? Is it possible to do it programmatically ?
Thanks
I think to achive this you will need multiple datasource configuration files and each database has its own SessionFactory object in an DAO which will permof DB operations.
For example :
SessionFactory sessionFactory1 = new Configuration().configure("oracleconfig.cfg.xml").buildSessionFactory();
SessionFactory sessionFactory2 = new Configuration().configure("mysqlconfig.cfg.xml").buildSessionFactory();
Related
I am trying to extract data from multiple databases in different servers. This has been successful after configuring different Data sources as shown in my code however i cannot see to configure 2 different Data sources on the same connection.
I have tried to create 2 beans within the config file but i would still need to set the Data source.
#Configuration
#EnableJpaRepositories(basePackages = {"balances.Repository.World"},
entityManagerFactoryRef = "ASourceEntityManager",transactionManagerRef = "ASourceTransactionManager")
#EnableTransactionManagement
public class World{
#Autowired
private Environment env;
#Bean
public LocalContainerEntityManagerFactoryBean ASourceEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(ASourceDatasource());
em.setPackagesToScan(new String("balances.Repository.World"));
em.setPersistenceUnitName("ASourceEntityManager");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<String, Object>();
properties.put("hibernate.dialect",env.getProperty("app.datasource.ASource.hibernate.dialect"));
properties.put("hibernate.show-sql",env.getProperty("app.datasource.ASource.show-sql"));
em.setJpaPropertyMap(properties);
return em;
}
#Bean
#ConfigurationProperties(prefix = "app.datasource.ASource")
public DataSource ASourceDatasource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("app.datasource.ASource.driverClassName"));
dataSource.setUrl(env.getProperty("app.datasource.ASource.url"));
dataSource.setUsername(env.getProperty("app.datasource.ASource.username"));
dataSource.setPassword(env.getProperty("app.datasource.ASource.password"));
return dataSource;
}
#ConfigurationProperties(prefix = "app.datasource.ASourceB")
public DataSource ASourceDatasource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("app.datasource.ASourceB.driverClassName"));
dataSource.setUrl(env.getProperty("app.datasource.ASourceB.url"));
dataSource.setUsername(env.getProperty("app.datasource.ASourceB.username"));
dataSource.setPassword(env.getProperty("app.datasource.ASourceB.password"));
return dataSource;
}
#Bean
public PlatformTransactionManager ASourceTransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
ASourceEntityManager().getObject());
return transactionManager;
}
After some thought i have come up with a workaround that might be a bit hacky but gets the job done.
Instead of declaring a new database connection for the second schema in my app.properties i have used one connection. I placed all my entities in one model package and used a native query to access the other schema. In the native query i would then specify the schema eg:
select * from DATABASE1.Id;
This solution does not scale well as it would create a lot of work when dealing with a large number of entities so if there is a way of specifying the schema in the repository that would also help.
I tried using the entity attributes to define my schema but jpa seems to be ignoring it and prefixing the table with the wrong schema for example if
i annotate my class with the following
#Table(name = "Payment", schema = "DATABASE1", catalog = "")
The resulting query would be "select * from DATABASE2.Payment" instead of
select * from DATABASE1.Payment
I am trying to configure two data sources for a Spring Boot project. Here is my configuration file for primary data source.
#PropertySource({"classpath:application-local.properties"})
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "primaryEntityManager",
basePackages = {"portal.api.repository"}
)
public class PrimaryDbConfig {
#Autowired
private Environment env;
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean primaryEntityManager() {
LocalContainerEntityManagerFactoryBean em
= new LocalContainerEntityManagerFactoryBean();
em.setDataSource(primaryDataSource());
em.setPackagesToScan(
new String[]{"portal.api.model"});
HibernateJpaVendorAdapter vendorAdapter
= new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto",
env.getProperty("app.datasource.spring.jpa.hibernate.ddl"));
properties.put("hibernate.dialect",
env.getProperty("hibernate.dialect"));
em.setJpaPropertyMap(properties);
return em;
}
#Primary
#Bean
public DataSource primaryDataSource() {
DriverManagerDataSource dataSource
= new DriverManagerDataSource();
dataSource.setDriverClassName(
env.getProperty("app.datasource.driver-class-name"));
dataSource.setUrl(env.getProperty("app.datasource.url"));
dataSource.setUsername(env.getProperty("app.datasource.username"));
dataSource.setPassword(env.getProperty("app.datasource.password"));
return dataSource;
}
#Primary
#Bean
public PlatformTransactionManager userTransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
primaryEntityManager().getObject());
return transactionManager;
}
}
The tables are generated but their names and column names are in camel case. However I would like to have the underscore names which spring boot has by default. For example ApiKey entity would be changed to table name api_key.
How do I configure Spring Boot to use the underscored naming strategy?
I think if you use #Column(name = "api_key") in your instance variable for your domain model it'll work.
e.g.
#Column(name = "api_key")
private String apiKey;
Reference from Official doc
By default, Spring Boot configures the physical naming strategy with
SpringPhysicalNamingStrategy. This implementation provides the same
table structure as Hibernate 4: all dots are replaced by underscores
and camel casing is replaced by underscores as well.
You can set the following property in application.yml to tell springboot which naming strategy to use:
spring:
jpa:
hibernate:
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
Similar post for reference:
java.sql.SQLSyntaxErrorException: Unknown column .JPA Entity Issue?
I want to add multiple tenant into my application using separate schema.My application is based on spring jpa and hibernate. I implement MultiTenantConnectionProvider and CurrentTenantIdentifierResolver.
And my configuration class is:
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource){
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setPackagesToScan("com.**.api.entity");
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
entityManagerFactory.setJpaVendorAdapter(hibernateJpaVendorAdapter);
Properties jpaProperties = new Properties();
jpaProperties.put("hibernate.globally_quoted_identifiers",true);
jpaProperties.put("hibernate.dialect",org.hibernate.dialect.MySQL5Dialect.class);
jpaProperties.put("hibernate.multi_tenant_connection_provider",multiTenantConnectionProvider);
jpaProperties.put("hibernate.tenant_identifier_resolver",currentTenantIdentifierResolver);
jpaProperties.put("hibernate.multiTenancy","SCHEMA");
entityManagerFactory.setJpaProperties(jpaProperties);
return entityManagerFactory;
}
And I use MapDataSourceLookup to save dataSources.It works.But it's a little problem. I must assign the packagesToScan.I want it to be a basic service.And some application depend on it.It seems that assign the packagesToScan is not a good practice.
Is there any better way to do it?
How can we integrate Hibernate OGM with Spring Data JPA, so that existing application containing Hibernate ORM can be used with Hibernate OGM.
This is the configuration i'm currently using for Hibernate ORM
#Bean(name = "jdbc")
public DriverManagerDataSource getDriverManager() {
DriverManagerDataSource driverManagerDataSource = new
DriverManagerDataSource(
env.getProperty(dataBase + ".url"), env.getProperty(dataBase +
".username"),
env.getProperty(dataBase + ".password"));
driverManagerDataSource.setDriverClassName(env.getProperty(dataBase +
".driver"));
return driverManagerDataSource;
}
#Bean(name = "japaImplementation")
public HibernateJpaVendorAdapter getHibernate() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setDatabasePlatform(env.getProperty(dataBase + ".dialect"));
vendorAdapter.setGenerateDdl(true);
vendorAdapter.setShowSql(true);
return vendorAdapter;
}
#Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean
getEntityManagerFactoryBean() {
LocalContainerEntityManagerFactoryBean factoryBean = new
LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(getDriverManager());
factoryBean.setJpaVendorAdapter(getHibernate());
factoryBean.setPackagesToScan("com.xyz.abc.entity");
return factoryBean;
}
I just had a quick glance at Hibernate OGM. It seems it is just a JPA implementation. So Spring Data JPA should work out of the box for it. Although up to now it does not get tested against it.
But it raises the question, why you would want to do that? There are already Spring Data modules for most, if not all of the data stores supported by Hibernate OGM. So why don't you use Spring Data MongoDB directly?
The projects are more alternatives to each other than something to let one run on top of the other. See this question for arguments from both sides.
I am using Spring Data JPA and trying to run query like this:
#Query(value="select i.content from Item i where i.itemOrder = :order")
List<String> findContentByItemOrder(#Param("order")Integer itemOrder);
but it throws exception:
org.hibernate.hql.internal.ast.QuerySyntaxException: Item is not mapped [select i.content from Item i where i.itemOrder = :order]
so when I run this:
#Query(value="select i.content from package.name.Item i where i.itemOrder = :order")
List<String> findContentByItemOrder(#Param("order")Integer itemOrder);
everything works like expected. My configuration:
#Bean
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("package.name");
factory.setDataSource(dataSource);
factory.setJpaProperties(createProperties());
factory.afterPropertiesSet();
return factory.getObject();
}
private Properties createProperties(){
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
properties.setProperty("hibernate.show_sql", "true");
properties.setProperty("hibernate.hbm2ddl.auto", "validate");
return properties;
}
I am using: Spring Data Jpa 1.3.1.RELEASE, Hiberante 4.2, Spring 3.2.1
The problem is that I don't want to put package.name for every class name in my Query.How to set Spring Data JPA for finding mapped class automatically ?