I haven't found a question on this topic so I'll ask. I've never actually tackled something which uses more than one data source. One example would be ETL which requires two data sources. How could such an application be designed?
Two data sources, two separate names. Inject each one by their respective bean IDs.
<bean id="fromDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${from.jdbc.driverClassName}"/>
<property name="url" value="${from.jdbc.url}"/>
<property name="username" value="${from.jdbc.username}"/>
<property name="password" value="${from.jdbc.password}"/>
</bean>
<context:property-placeholder location="from.jdbc.properties"/>
<bean id="toDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${to.jdbc.driverClassName}"/>
<property name="url" value="${to.jdbc.url}"/>
<property name="username" value="${to.jdbc.username}"/>
<property name="password" value="${to.jdbc.password}"/>
</bean>
<context:property-placeholder location="to.jdbc.properties"/>
You'd want to have a single DAO, but two instances of it - each with their own data source. One would SELECT from the source, the other would INSERT into the target.
A better way might be to forego Spring and just use bulk transfer mechanisms built into the databases.
Related
This is a question that was asked in an interview .
The question was that a bean has certain properties which we configure in .xml file and then we inject it but let's say that one does not know that the properties or the properties will be different for different Beans . So how will we make that bean so that we are able to configure it in runtime ?
I think externalizing the bean values, something like:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>classpath:com/foo/jdbc.properties</value>
</property>
</bean>
<bean id="dataSource" destroy-method="close"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
then following the example having your jdbc.properties file:
jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:hsql://production:9002
jdbc.username=sa
jdbc.password=root
the properties can be configured at runtime
The problem
I have an application build on Spring 4, Hibernate 5 and Spring Data JPA 1.7. I use PostgresSQL as database. I'd like to use Hibernate's support for multi tenancy, but have problem with correctly implementing MultiTenantConnectionProvider. I'd like to use SCHEMA stratagey for separating tenants and I'd prefer to use single DataSource.
My current implementation of MultiTenantConnectionProvider's method getConnection() looks like this:
#Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
final Connection connection = getAnyConnection();
try {
connection.createStatement().execute("SET SCHEMA '" + tenantIdentifier + "'");
}
catch (SQLException e) {
throw new HibernateException("Could not alter JDBC connection to specified schema [" + tenantIdentifier + "]", e);
}
return connection;
}
I take the connection from my DataSource, which I inject by implementing interface ServiceRegistryAwareService, but I'm not sure that this is a right way.
Method gets called when it should with correct tenantIdentifier (comming from my implementation of CurrentTenantIdentifierResolver), statement is executed, but in practise, it is useless. Problem is, that queries generated by Hibernate contain fully qualified names of tables including default schema. Can I tell hibernate to omit default schema from queries? Or should I use completely different approach?
My configuration
I don't wanna clutter my question with too much configuration, I'll paste here what I believe is relevant. If I missed something important, please let me know.
This is part of my application context xml
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="pu" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false" />
<property name="databasePlatform" value="org.hibernate.dialect.PostgreSQL9Dialect" />
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
</bean>
Side question
Is there any difference between hibernate.multiTenancy values SCHEMA and DATABASE, from Hibernate's point of view? I understand the conceptual difference between these two, but from looking at the source code, it seems to me like these two are completely interchangeable and all the logic is hidden in the implementation of MultiTenantConnectionProvider. Am I missing something?
I have read Spring Fundamentals. Actually i visited many sites to know how to configure mysql database to spring project. But i have failed to get specific solution about it. so please help me to solve this problem.
<bean name="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/database" />
<property name="username" value="user" />
<property name="password" value="pass" />
</bean>
Springframework documentation
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-datasource
I'm looking to see what's the best way to use one DataSources in Spring but be able to switch the database from within the Java code? Below are my two DataSources and they go to the same database server but different databases.
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.sybase.jdbc3.jdbc.SybDataSource" />
<property name="url"
value="jdbc:sybase:Tds:10.20.30.40:50/DATABASE_EMS" />
<property name="username" value="userid" />
<property name="password" value="derp" />
</bean>
<bean id="dataSourceMain" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.sybase.jdbc3.jdbc.SybDataSource" />
<property name="url"
value="jdbc:sybase:Tds:10.20.30.40:50/DATABASE" />
<property name="username" value="userid" />
<property name="password" value="derp" />
</bean>
I have them bound to their own respective bean but I'm looking at my legacy code and it's going to be VERY awkward to implement this with 2 separate beans. Is there any ideas/thoughts on how to be able to use one DataSource and switch databases when I need to?
You can do this by extending the Spring's AbstractRoutingDataSource and wrapping your existing data sources in it. Check this article for details. Quoting from the article:
The general idea is that a routing DataSource acts as an intermediary
– while the 'real' DataSource can be determined dynamically at runtime
based upon a lookup key.
Also see similar questions on SO:
Using AbstractRoutingDataSource to dynamically change the database schema/catalog
Reading from multiple Db's with same Persistence Unit?
How to create Dynamic connections (datasource) in spring using JDBC
There are many ways you can do this. For example, you can create a service class DatasourceSelectorService, and based on some input (eg: configuration file/user input) it chooses the datasource's bean accordingly.
All other classes requiring a datasource should obtain it via this DatasourceSelectorService.
Is it possible to define a datasource connector in a Spring controller ?
I'm working on a tool : synchronize a source table to a target table.
I would define source and target in my controller (to synchronize different databases - in my view I can select different source and target databases).
Actually, I define my datasource in file call : datasource.xml
My code :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config />
<bean id="sourceDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/source"/>
<!--<property name="url" value="jdbc:mysql://linkSource"/>-->
<property name="username" value="username"/>
<property name="password" value="password"/>
</bean>
<bean id="targetDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/target"/>
<!--<property name="url" value="jdbc:mysql://linkTarget"/>-->
<property name="username" value="username"/>
<property name="password" value="password"/>
</bean>
</beans>
Thank you for your help !
Thank you for your help !
But I think I put my question badly.
Actually, I have in my sync-servelt.xml (just part) :
<!--sync query beans-->
<bean id="sourceDatasetQueryBean" class="ds.sync.db.SyncDatasetQuery" name="sourceDatasetsQuery">
<property name="dataSource" ref="sourceDataSource"/>
</bean>
<bean id="targetDatasetQueryBean" class="ds.sync.db.SyncDatasetQuery" name="targetDatasetsQuery">
<property name="dataSource" ref="targetDataSource"/>
</bean>
<bean id="sourceDatasetDescriptionQueryBean" class="ds.sync.db.SyncDatasetDescriptionQuery" name="sourceDatasetsDescriptionQuery">
<property name="dataSource" ref="sourceDataSource"/>
</bean>
<bean id="targetDatasetDescriptionQueryBean" class="ds.sync.db.SyncDatasetDescriptionQuery" name="targetDatasetsDescriptionQuery">
<property name="dataSource" ref="targetDataSource"/>
</bean>
...more...
And, in my controller I'm using :
#Autowired
#Qualifier("sourceDatasetQueryBean")
protected SyncDatasetQuery m_datasetQuerySource;
#Autowired
#Qualifier("targetDatasetQueryBean")
protected SyncDatasetQuery m_datasetQueryTarget;
#Autowired
#Qualifier("sourceDatasetDescriptionQueryBean")
protected SyncDatasetDescriptionQuery m_datasetDescriptionQuerySource;
#Autowired
#Qualifier("targetDatasetDescriptionQueryBean")
protected SyncDatasetDescriptionQuery m_datasetDescriptionQueryTarget;
...more...
I have 11 tables to sync between source and target...
Is there a way to group my query beans ?
My synchronizations must be performed on several databases.
For example, I have 3 sites in different places, 1 site is SOURCE (A), 2 sites are TARGET (B & C) ; with a form (made with YUI), I should be able to sync A->B and A->C.
To sum up :
1- with my form I select a SOURCE, and a TARGET (serveral databases),
2- my form send (in Ajax), the selected SOURCE and selected TARGET to my controller,
3- my controller points to the good database.
What is the best way to do this ?
Using a Factory ?
Using setDataSource ?
Thank you for help.
You should be able to use the following syntax to achieve what you want (see Spring 2.x docs):
#Autowired
#Qualifier("targetDataSource")
DataSource targetDataSource;
#Autowired
#Qualifier("sourceDataSource")
DataSource sourceDataSource;
So assuming your data sources are defined correctly it's only a matter of injecting them into your Controller:
<bean id="myController" class="...">
<property name="sourceDS" ref="sourceDataSource" />
<property name="targetDS" ref="targetDataSource" />
....
</bean>
If you don't want to be messing with spring xml files, and relay in properties or any other GUI to define those datasources at runtime, you might use:
applicationContext.getBean(bean,object[])
Be aware that is not a good practise with spring (even that it is quite handy sometimes).
This way you define your beans expecting constructor arguments and supply those arguments as part of the array. This way you create as many datasources you need at runtime getting those from wherever you want to store the information.
Finally, by using DriverManagerDataSource, and using setter, I can redefine my dataSource selected (target and source) dynamically in my controller.
I just need to use :
setDriverManagerDataSource(m_sourceDataSource);
and m_datasetQuerySource.setDataSource(dataSource); (SOURCE)
Same play with target and all tables.
I see also other way to do that :
http://blog.springsource.com/2007/01/23/dynamic-datasource-routing/
http://grails.org/Spring+Bean+Builder