Hi this is what I am looking to do -
I have three databases - each exactly the same - one is primary and two and three are back ups.
I am using hibernate and spring to connect to the data base.I have spring application context file configured with 3 session factories, and 3 corresponding data sources.
I was wondering if there is a way using spring where if the application is not able to connect to the database 1 (an exception is thrown) it will connect to database 2 - and in turn is database 3 is down it will connect to 3 and proceed.
What would be the best way to implement this? I have read about AbstractRoutingDataSource ..but not sure how to make use of that in this case..also if there are other ideas.. Would appreciate some directions. Thanks!
this is my config in application context xml -
<bean id="dataSource1" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="$g{jdbc.driverClassName}" />
<property name="jdbcUrl" value="$g{url1}" />
<property name="user" value="$l{uid1}" />
<property name="password" value="$l{pwd1}" />
<property name="minPoolSize" value="$g{jdbc.minPoolSize}" />
<property name="maxPoolSize" value="$g{jdbc.maxPoolSize}" />
<property name="preferredTestQuery" value="$g{jdbc.preferredTestQuery}" />
<property name="testConnectionOnCheckout" value="$g{jdbc.testConnectionOnCheckout}" />
</bean>
<bean id="sessionFactory1"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource1" />
<property name="packagesToScan">
<list>
<value>com.model</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
<prop key="hibernate.dialect">$g{jdbc.dialect}</prop>
<prop key="hibernate.show_sql">$g{jdbc.show_sql}</prop>
</props>
</property>
</bean>
<bean id="dataSource2" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="$g{jdbc.driverClassName}" />
<property name="jdbcUrl" value="$g{url2}" />
<property name="user" value="$l{uid2}" />
<property name="password" value="$l{pwd2}" />
<property name="minPoolSize" value="$g{jdbc.minPoolSize}" />
<property name="maxPoolSize" value="$g{jdbc.maxPoolSize}" />
<property name="preferredTestQuery" value="$g{jdbc.preferredTestQuery}" />
<property name="testConnectionOnCheckout" value="$g{jdbc.testConnectionOnCheckout}" />
</bean>
<bean id="sessionFactory2"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource2" />
<property name="packagesToScan">
<list>
<value>com.model</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
<prop key="hibernate.dialect">$g{jdbc.dialect}</prop>
<prop key="hibernate.show_sql">$g{jdbc.show_sql}</prop>
</props>
</property>
</bean>
<bean id="dataSource3" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="$g{jdbc.driverClassName}" />
<property name="jdbcUrl" value="$g{url3}" />
<property name="user" value="$l{uid3}" />
<property name="password" value="$l{pwd3}" />
<property name="minPoolSize" value="$g{jdbc.minPoolSize}" />
<property name="maxPoolSize" value="$g{jdbc.maxPoolSize}" />
<property name="preferredTestQuery" value="$g{jdbc.preferredTestQuery}" />
<property name="testConnectionOnCheckout" value="$g{jdbc.testConnectionOnCheckout}" />
</bean>
<bean id="sessionFactory3"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource3" />
<property name="packagesToScan">
<list>
<value>com.model</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
<prop key="hibernate.dialect">$g{jdbc.dialect}</prop>
<prop key="hibernate.show_sql">$g{jdbc.show_sql}</prop>
</props>
</property>
</bean>
<bean id="transactionManager1"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory1" />
</bean>
<bean id="transactionManager2"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory2" />
</bean>
<bean id="transactionManager3"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory3" />
</bean>
There is a way to achieve this by using Spring Abstract Data Source Routing mechanism -
https://spring.io/blog/2007/01/23/dynamic-datasource-routing/
Related
I am trying to use c3pO connection pooling but getting below error:
Unknown system variable 'tx_isolation'
I am using below jars:
mysql-connector-java-8.0.11.jar
c3p0-0.9.5.3.jar
mchange-commons-java-0.2.15.jar
And below configuration:
<bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="com.mysql.cj.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/customer_tracker?useSSL=false&serverTimezone=UTC" />
<property name="user" value="root" />
<property name="password" value="root" />
<!-- these are connection pool properties for C3P0 -->
<property name="minPoolSize" value="3" />
<property name="maxPoolSize" value="10" />
<property name="maxIdleTime" value="30000" />
</bean>
<!-- Step 2: Setup Hibernate session factory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="packagesToScan" value="com.springdemo.entity" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
I'm having two databases running in parallel.
I created two configs with different GenericDAOs/SessionFactories for each one, however the second SessionFactory to be instantiated have issues. When I try to getCurrentSession() I get this error : org.hibernate.HibernateException: No Session found for current thread.
Config1.xml :
<bean id="mainDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/main" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<bean id="mainSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="mainDataSource" />
<property name="annotatedClasses">
<list>
<value>com.avocat.domain.entities.main.User</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean id="mainTransactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="dataSource" ref="mainDataSource" />
<property name="sessionFactory" ref="mainSessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="mainTransactionManager" />
<context:annotation-config />
Config2.xml :
<bean id="fakeDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/fake" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<bean id="fakeSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="fakeDataSource" />
<property name="annotatedClasses">
<list>
<value>com.avocat.domain.entities.intra.Bla</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean id="fakeTransactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="dataSource" ref="fakeDataSource" />
<property name="sessionFactory" ref="fakeSessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="fakeTransactionManager" />
<context:annotation-config />
MainGenericDAO :
#Autowired
#Qualifier("mainSessionFactory")
private SessionFactory mainSessionFactory;
protected Session currentSession()
{
return mainSessionFactory.getCurrentSession();
}
FakeGenericDAO :
#Autowired
#Qualifier("fakeSessionFactory")
private SessionFactory fakeSessionFactory;
protected Session currentSession()
{
return fakeSessionFactory.getCurrentSession();
}
Config1 is declared before Config2.
Also, queries using MainGenericDAO/MainSessionFactory are OK.
But currentSession() from FakeGenericDAO returns the error.
It seems that the transaction is not created on your second DAO for the FakeSessionFactory. You must use #Transactional("fakeTransactionManager") on the FakeGenericDAO.
I would like to setup a RDS Read Replica to forward some of the read requests to it. I've annotated all my "read" Dao methods with:
#Transactional(readOnly = true)
Now I am struggling with datasource configuration. I expected that it would be really easy, but it seems it isn't. How can I tell the datasource/hibernate that there is a read replica available on certain endpoint?
Currently my configuration looks like:
<bean id="mainDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://${master-url}:3306/${db-name}?useSSL=true&requireSSL=true&verifyServerCertificate=false"/>
<property name="user" value="${user}"/>
<property name="password" value="${password}"/>
<!-- these are C3P0 properties -->
<property name="acquireIncrement" value="3"/>
<property name="minPoolSize" value="3"/>
<property name="maxPoolSize" value="10"/>
<property name="maxIdleTime" value="3600"/>
<!-- 1 hour -->
<property name="maxConnectionAge" value="7200"/>
<property name="maxIdleTimeExcessConnections" value="600"/>
<property name="idleConnectionTestPeriod" value="60"/>
<property name="testConnectionOnCheckin" value="true"/>
<property name="testConnectionOnCheckout" value="false"/>
<property name="preferredTestQuery" value="SELECT 1"/>
</bean>
<bean id="mainSessionFactory" name="mainSessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" depends-on="mainDataSource">
<property name="packagesToScan">
<list>
<value>com....</value>
</list>
</property>
<property name="dataSource" ref="mainDataSource"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.connection.tinyInt1isBit">true</prop>
<prop key="hibernate.connection.transformedBitIsBoolean">true</prop>
<prop key="hibernate.hbm2ddl.auto">none</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.connection.CharSet">UTF-8</prop>
<prop key="hibernate.connection.characterEncoding">UTF-8</prop>
<prop key="hibernate.connection.useUnicode">true</prop>
<prop key="hibernate.jdbc.batch_size">40</prop>
</props>
</property>
</bean>
Any help/advice would be highly appreciated!
Best Regards,
Maksim
I'm working on a web application that uses Spring MVC 3 and Hibernate
I want to use 2 datasource MySql and Oracle databases for my web application,
I've been read many tutorial and problem solving for "spring-hibernate multiple datasource/database"
for example :
directjump2java.blogspot.com
stackoverflow
forum spring
and etc.
but when every single time I run it, the config just read my first database config (MySql)
and show this error Table 'db_prod.ksei_lookup_holiday' doesn't exist db.prod is my first database(MySql) and KSEI_LOOKUP_HOLIDAY is my second database (Oracle),
this is my spring.xml
<tx:annotation-driven transaction-manager="transactionManager"/>
<tx:annotation-driven transaction-manager="transactionManagerSOAAPP"/>
<context:annotation-config />
<context:component-scan base-package="prod.support" />
<!-- Database MySql, Desktop -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/db_prod" />
<property name="username" value="root" />
<property name="password" value="shikamaru" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration"></property>
<property name="dataSource" ref="dataSource"></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="packagesToScan" value="prod.support.model.splatter" />
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory">
</bean>
<!-- Database Oracle, Schema : SOAAPP -->
<bean id="dataSourceSOAAPP" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#localhost:1521:XE" />
<property name="username" value="splatter" />
<property name="password" value="shikamaru" />
</bean>
<bean id="sessionFactorySOAAPP"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration"></property>
<property name="dataSource" ref="dataSource"></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="packagesToScan" value="prod.support.model.soaapp" />
</bean>
<bean id="transactionManagerSOAAPP"
class="org.springframework.orm.hibernate3.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactorySOAAPP">
</bean>
this is my DAO Implementation for my first database (MySql)
#Repository
#Qualifier(value="sessionFactory")
public class UserDaoImpl extends HibernateDaoSupport implements UserDao{
#Autowired
private UserDaoImpl(SessionFactory sessionFactory){
setSessionFactory(sessionFactory);
}
this is my DAO Implementation for my second database (Oracle)
#Repository
#Qualifier(value="sessionFactorySOAAPP")
public class UpdateKSEIDaoImpl extends HibernateDaoSupport implements UpdateKSEIDao{
#Autowired
private UpdateKSEIDaoImpl(SessionFactory sessionFactorySOAAPP){
setSessionFactory(sessionFactorySOAAPP);
}
any help will be pleasure :)
The problem is that you have used
<property name="dataSource" ref="dataSource"></property> in sessionFactorySOAAPP.
You should have used <property name="dataSource" ref="dataSourceSOAAPP"></property>
If you check "sessionFactorySOAAPP" then the below property name should be 'dataSourceSOAAPP' not the 'dataSource'.
this my configuration file:
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/gl?characterEncoding=UTF-8" />
<property name="username" value="root" />
<property name="password" value="2238295" />
</bean>
<bean id="mainDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/gl_main?characterEncoding=UTF-8" />
<property name="username" value="root" />
<property name="password" value="2238295" />
</bean>
<!-- Hibernate 4 SessionFactory Bean definition -->
<bean id="sfAccounting"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.gl.domain.accounting" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.connection.useUnicode">true</prop>
<prop key="hibernate.connection.characterEncoding">UTF-8</prop>
<prop key="hibernate.connection.charSet">UTF-8</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect
</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
</bean>
<!-- Hibernate 4 SessionFactory Bean definition -->
<bean id="sfCommon"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="mainDataSource" />
<property name="packagesToScan" value="com.gl.domain.common" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.connection.useUnicode">true</prop>
<prop key="hibernate.connection.characterEncoding">UTF-8</prop>
<prop key="hibernate.connection.charSet">UTF-8</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect
</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
</bean>
<tx:annotation-driven transaction-manager="txnManagerAccounting"/>
<tx:annotation-driven transaction-manager="txnManagerCommon"/>
<bean id="txnManagerAccounting"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sfAccounting" />
</bean>
<bean id="txnManagerCommon"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sfCommon" />
</bean>
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
#geoand is correct in the error he spotted. Other than that the context xml seems correct and works for me.
However, for me, this only works if #qualifier is with the #Autowired.
#Repository
public class BusinessDaoImpl implements BusinessDao
{
#Autowired
#Qualifier(value="sessionFactory")
SessionFactory sessionFactory;
I have below configuration in my spring config file. I am using Spring3, Hibernate4 and Tomcat7.
<jee:jndi-lookup id="wcDataSource" jndi-name="java:comp/UserTransaction" resource-ref="false" environment-ref="remoteEnv" />
<util:properties id="remoteEnv">
<prop key="java.naming.provider.url">jnp://jndi.myURL.me:1099</prop>
<prop key="java.naming.factory.url.pkgs">org.jboss.naming:org.jnp.interfaces</prop>
<prop key="java.naming.factory.initial">org.jnp.interfaces.NamingContextFactory</prop>
<prop key="jnp.disableDiscovery">true</prop>
</util:properties>
<bean id="dataSourceKS" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${driverClassName}" />
<property name="jdbcUrl" value="${url}" />
<property name="user" value="${username}" />
<property name="password" value="${password}" />
<!-- pool sizing -->
<property name="initialPoolSize" value="15" />
<property name="minPoolSize" value="10" />
<property name="maxPoolSize" value="20" />
<property name="acquireIncrement" value="3" />
<property name="maxStatements" value="6000" />
<property name="maxStatementsPerConnection" value="300" />
</bean>
<bean name="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSourceKS"/>
<property name="annotatedClasses">
<list>
<value>com.sample.MyBean</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.NoCacheProvider</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.use_sql_comments">true</prop>
<prop key="hibernate.jdbc.batch_size">50</prop>
</props>
</property>
</bean>
Now how can i configure JTATransactionManager here to use #Transactional? Here i have wcDataSource and dataSourceKS. Thanks!
Thanks!
The JtaTransactionManager does not need to know about the DataSource, or any other specific resources, because it uses the container’s global transaction management infrastructure.
So conf file should look like this
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
See http://lafernando.com/2011/01/05/xa-transactions-with-apache-dbcp/ which does it in code but which you should be able to translate to a spring configuration.
Which would result in something like this.
<jee:jndi-lookup id="userTransaction" jndi-name="java:comp/UserTransaction" resource-ref="false" environment-ref="remoteEnv" />
<jee:jndi-lookup id="jtaTransactionManager" jndi-name="java:comp/TransactionManager" resource-ref="false" environment-ref="remoteEnv" />
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<constructor-arg ref="userTransaction"/>
<constructor-arg ref="jtaTransactionManager"/>
</bean>
<util:properties id="remoteEnv">
<prop key="java.naming.provider.url">jnp://jndi.myURL.me:1099</prop>
<prop key="java.naming.factory.url.pkgs">org.jboss.naming:org.jnp.interfaces</prop>
<prop key="java.naming.factory.initial">org.jnp.interfaces.NamingContextFactory</prop>
<prop key="jnp.disableDiscovery">true</prop>
</util:properties>
<bean id="oracleXaDataSource" class="oracle.jdbc.xa.client.OracleXADataSource">
<property name="user" value="${username}" />
<property name="password" value="${password}" />
<property name="url" value="${url}" />
</bean>
<bean id="dataSourceKS" class="org.apache.commons.dbcp.managed.BasicManagedDatasource">
<property name="transactionManager" ref="jtaTransactionManager" />
<property name="xaDataSourceInstance" ref="oracleXaDataSource" />
<property name="initialPoolSize" value="15" />
<property name="minPoolSize" value="10" />
<property name="maxPoolSize" value="20" />
<property name="acquireIncrement" value="3" />
<property name="maxStatements" value="6000" />
<property name="maxStatementsPerConnection" value="300" />
</bean>
<bean name="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="jtaDataSource" ref="dataSourceKS"/>
// .. other hibernate properties
</bean>
Note the change to commons-dbcp as c3p0 doesn't have XA capable implementations.