Multiple database Schema with Spring+Hibernate+JPA - spring

I have same database schema database_1 and database_2 and want to configuration of these two database(database schema is same) and decide run time which database is use.
My persistence.xml is as below:
<persistence-unit name="first" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.model.AboutUs</class>
<class>com.model.AccessCards</class>
<properties>
<property name="hibernate.dialect" value="com.util.customMySQLDialect" />
<property name="hibernate.hbm2ddl.auto" value="none" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider" />
<property name="hibernate.jdbc.batch_size" value="20"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
</properties>
</persistence-unit>
Persistence name second configure here as below :
<persistence-unit name="second" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.model.AboutUs</class>
<class>com.model.AccessCards</class>
<properties>
<property name="hibernate.dialect" value="com.util.customMySQLDialect" />
<property name="hibernate.hbm2ddl.auto" value="none" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider" />
<property name="hibernate.jdbc.batch_size" value="20"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
</properties>
</persistence-unit>
Both persistence units load same classes .
and now my database-configure.xml as where i configure persistence unit with data source. as below first persistence unit name configare with datasource name datasource as :
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="first" />
<property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
</bean>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${datasource.driverClassName}" />
<property name="jdbcUrl" value="${datasource.url}" />
<property name="user" value="${datasource.username}" />
<property name="password" value="${datasource.password}" />
<property name="acquireIncrement" value="1" />
<property name="acquireRetryAttempts" value="1" />
<property name="maxIdleTime" value="300" />
<property name="maxPoolSize" value="20" />
<property name="minPoolSize" value="3" />
<property name="maxStatements" value="300" />
<property name="testConnectionOnCheckin" value="true" />
</bean>
Now this code for configure second persistence unit name with data source name datasource5 as below :
<bean id="transactionManager5" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory5" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource5" />
<property name="persistenceUnitName" value="second" />
<property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
</bean>
<bean id="dataSource5" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${datasource.driverClassName}" />
<property name="jdbcUrl" value="${datasource5.url}" />
<property name="user" value="${datasource5.username}" />
<property name="password" value="${datasource5.password}" />
<property name="acquireIncrement" value="1" />
<property name="acquireRetryAttempts" value="1" />
<property name="maxIdleTime" value="300" />
<property name="maxPoolSize" value="20" />
<property name="minPoolSize" value="3" />
<property name="maxStatements" value="300" />
<property name="testConnectionOnCheckin" value="true" />
</bean>
Now i use entity manager for save data in database and i am using mysql database . I got entity manager with persistence unit name first and second .
#PersistenceContext(unitName="first")
private EntityManager entityManager;
#PersistenceContext(unitName="second")
private EntityManager entityManager2;
Now entity manager save data in database using persist( object) method successfully .
entityManager.persist(project);
and entityManager2 save data in database using persist( object ) method successfully (No Exception here). But data does not store in database datbase_2 .
entityManager2.persist(project);
If I change the order of persistence unit first and second in persistence.xml then entityManager2 save data in database and entitymanager does not save data in database .
Any one have idea how i can make multiple entitymanager for same database schema .

There are a few limitations:
#Transactional corresponds to single TransactionManager.
JpaTransactionManager corresponds to single EntityManager(Factory).
Thus use separate methods with #Transactional annotation for each transaction manager:
#Transactional(transactionManager = "tmBeanName")
After that entity managers will work fine.
Also, some workaround exists to break the second limitation (DO NOT USE IT in this case):
It is possible to use single JtaTransactionManager instead of several JpaTransactionManager: distributed transaction will cover both entity managers and they will work fine too.

Related

multiple entityManagerFactory for 2 different datasources

I want keep 2 datasources for 2 different databases (both are mysql) like below :
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
<property name="database" value="MYSQL" />
</bean>
<bean id="dataSource-A"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url-A}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="entityManagerFactory-A"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource-A" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<!-- spring based scanning for entity classes -->
<property name="packagesToScan" value="com.package-A" />
</bean>
<bean id="dataSource-B"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url-B}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="entityManagerFactory-B"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource-B" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<!-- spring based scanning for entity classes -->
<property name="packagesToScan" value="com.package-B" />
</bean>
Now when i do simply this, beanInitializer gives error that entityManagerFactory is not found.
How can i have multiple entityManagerFactory, for multiple data base and what is best way to do in xml.
I googled quite a lot, but none is able to solve my problem.
It works well if i define only one entityManagerFactory, I am just stuck to have miltiple entityManagerFactory in same application context.
Below is the example for keeping multiple persistence unit for different type of database. Similarly 2 unit can be kept for both of your sql databases.
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="oraPersistent" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>com.kulhade.us.ora.entity.BilltoAddress</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
<validation-mode>AUTO</validation-mode>
<properties>
<property name="javax.persistence.jdbc.driver" value="${db.driver}"/>
<property name="javax.persistence.jdbc.url" value="${db.url}"/>
<property name="javax.persistence.jdbc.user" value="${db.username}"/>
<property name="javax.persistence.jdbc.password" value="${db.password}"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.generate_statistics" value="true"/>
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory"/>
<property name="hibernate.jdbc.batch_size" value="50"/>
</properties>
</persistence-unit>
<persistence-unit name="mongoPersistent" transaction-type="JTA">
<!-- Use Hibernate OGM provider: configuration will be transparent -->
<provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider>
<class>com.kulhade.us.mongo.entity.Sample</class>
<class>com.kulhade.us.mongo.entity.SampleLine</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.ogm.datastore.provider" value="mongodb" />
<property name="hibernate.ogm.datastore.database" value="${mongodb.name}"/>
<property name="hibernate.ogm.mongodb.host" value="${mongodb.host}"/>
<property name="hibernate.ogm.datastore.port" value="${mongodb.port}"/>
<!--<property name="hibernate.ogm.datastore.document.association_storage" value="ASSOCIATION_DOCUMENT"/>
<property name="hibernate.ogm.mongodb.association_document_storage" value="COLLECTION_PER_ASSOCIATION"/>-->
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossStandAloneJtaPlatform"/>
</properties>
</persistence-unit>
</persistence>
These multiple persistence unit can be used in Spring orm. Below is the example for it.
<bean id="pum" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="persistenceXmlLocations">
<list>
<value>org/springframework/orm/jpa/domain/persistence-multi.xml</value>
<value>classpath:/my/package/**/custom-persistence.xml</value>
<value>classpath*:META-INF/persistence.xml</value>
</list>
</property>
<property name="dataSources">
<map>
<entry key="localDataSource" value-ref="local-db"/>
<entry key="remoteDataSource" value-ref="remote-db"/>
</map>
</property>
<!-- if no datasource is specified, use this one -->
<property name="defaultDataSource" ref="remoteDataSource"/>
</bean>
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager" ref="pum"/>
<property name="persistenceUnitName" value="myCustomUnit"/>
</bean>

Configure Multiple JPA Repositories in CrudRepository approach

I am trying to configure the multiple JPA repositories in my web application. Currently I have one Repository as mentioned below. I am using Crud Repository
<jpa:repositories base-package="com.mypackage1" factory-class="org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean" transaction-manager-ref="transactionManager" entity-manager-factory-ref="entityManagerFactory">
<repository:include-filter type="assignable" expression="com.MyFirstRepository"/>
</jpa:repositories>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.mypackage1.Model" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="database" value="H2" />
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:database/~test" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
If I need to configure multiple repositories,
<bean id="entityManagerFactory2"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource2" />
<property name="packagesToScan" value="com.mypackage2.Model" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="database" value="H2" />
</bean>
</property>
</bean>
<bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory2" />
</bean>
<bean id="dataSource2"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:database/~test2" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
I am not able to find any appropriate configuratiuon for this.
Appreciate help on this.

Can I use multiple C3P0 datasources for DB instance?

I was wondering if I can run multiple c3p0 datasources for one DB, something like:
<bean id="dataSource1" class = "com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${db.driverClassName}"/>
<property name="jdbcUrl" value="${db.url}/schema1"/>
<property name="user" value="${db.username}"/>
<property name="password" value="${db.password}"/>
<property name="acquireIncrement" value="1" />
<property name="idleConnectionTestPeriod" value="100"/>
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="50" />
<property name="maxIdleTime" value="1800" />
</bean>
<bean id="dataSource2" class = "com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${db.driverClassName}"/>
<property name="jdbcUrl" value="${db.url}/schema2"/>
<property name="user" value="${db.username}"/>
<property name="password" value="${db.password}"/>
<property name="acquireIncrement" value="1" />
<property name="idleConnectionTestPeriod" value="100"/>
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="50" />
<property name="maxIdleTime" value="1800" />
</bean>
They will be used by difference persistence services.
Thanks.
That's absolutely fine. You'll run into some configuration issues like:
autowiring DataSource by type won't work
#Transactional/declarative transactions will work only against one, selected DataSource. Alternatively you'll have to manually tell which transaction manager you want to use (thus you'll need two transaction managers as well: transactionManager1 and transactionManager2):
#Transactional("transactionalManager2")
Besides, there's nothing wrong with this configuration. Actually it's a pretty good idea (+1): if some layers/components of your application saturate the pool, others can still operate.
The only thing I recommend is to use lesser known abstract/parent bean declarations to avoid repetition:
<bean id="dataSource" abstract="true" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${db.driverClassName}"/>
<property name="user" value="${db.username}"/>
<property name="password" value="${db.password}"/>
<property name="acquireIncrement" value="1" />
<property name="idleConnectionTestPeriod" value="100"/>
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="50" />
<property name="maxIdleTime" value="1800" />
</bean>
<bean id="dataSource1" parent="dataSource">
<property name="jdbcUrl" value="${db.url}/schema1"/>
</bean>
<bean id="dataSource2" parent="dataSource">
<property name="jdbcUrl" value="${db.url}/schema2"/>
</bean>
See also:
What is meant by abstract="true" in spring?

EhCache CacheManager with multiple EntityManagerFactory

And one entityManagerFactory in spring-server.xml.
But i must generate one more entityManager, and i do it with
Persistence.createEntityManagerFactory("myotherpersistenceunitname");
but i get exception
Caused by: net.sf.ehcache.CacheException: Another unnamed CacheManager already exists in the same VM. Please provide unique names for each CacheManager in the config or do one of following:
1. Use one of the CacheManager.create() static factory methods to reuse same CacheManager with same name or create one if necessary
2. Shutdown the earlier cacheManager before creating new one with same name.
The source of the existing CacheManager is: DefaultConfigurationSource [ ehcache.xml or ehcache-failsafe.xml ]
at net.sf.ehcache.CacheManager.assertNoCacheManagerExistsWithSameName(CacheManager.java:457)
at net.sf.ehcache.CacheManager.init(CacheManager.java:354)
at net.sf.ehcache.CacheManager.<init>(CacheManager.java:242)
at net.sf.ehcache.hibernate.EhCacheRegionFactory.start(EhCacheRegionFactory.java:70)
spring.xml:
<context:property-placeholder location="classpath:application.properties"/>
<context:component-scan base-package="merve.web.app" >
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation" />
</context:component-scan>
<context:annotation-config/>
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" />
<cache:annotation-driven />
<bean id="properties" class="merve.web.app.configuration.PropertyResourceConfiguration" />
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="myPU"/>
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="${database.target}"/>
<property name="showSql" value="${database.showSql}" />
</bean>
</property>
</bean>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${database.driver}"/>
<property name="jdbcUrl" value="${database.url}"/>
<property name="user" value="${database.username}"/>
<property name="password" value="${database.password}"/>
<property name="minPoolSize" value="2"/>
<property name="maxPoolSize" value="10"/>
<property name="breakAfterAcquireFailure" value="false"/>
<property name="acquireRetryAttempts" value="3"/>
<property name="idleConnectionTestPeriod" value="300" />
<property name="testConnectionOnCheckout" value="true" />
</bean>
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="jamesEntityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="jamesPU"/>
<property name="dataSource" ref="dataSourceJames" />
<property name="persistenceXmlLocation" value="classpath:META-INF/james-persistence.xml"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
<property name="showSql" value="true" />
</bean>
</property>
</bean>
<bean id="dataSourceJames" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="org.apache.derby.jdbc.EmbeddedDriver"/>
<property name="jdbcUrl" value="jdbc:derby:../var/store/derby;create=true"/>
<property name="user" value="app"/>
<property name="password" value="app"/>
<property name="minPoolSize" value="2"/>
<property name="maxPoolSize" value="10"/>
<property name="breakAfterAcquireFailure" value="false"/>
<property name="acquireRetryAttempts" value="3"/>
<property name="idleConnectionTestPeriod" value="300" />
<property name="testConnectionOnCheckout" value="true" />
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>messages</value>
</list>
</property>
</bean>
<!-- Ehcache library setup -->
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:shared="true" p:config-location="classpath:ehcache.xml"/>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" >
<property name="cacheManager"><ref local="ehcache"></ref></property>
</bean>
<dwr:configuration/>
<dwr:annotation-scan base-package="tuxi.web.app.service.dwr" scanRemoteProxy="true" scanDataTransferObject="true"/>
<dwr:url-mapping />
<dwr:controller id="dwrController"/>
</beans>
The problem, described here, and fixed in the source is not using the EhCache singleton correctly. The answer depends on which version of spring-context-support AND which version of EhCache you are using. For both, you need to be using EhCache 2.6 or greater:
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.6.0</version>
</dependency>
Next, determine what to do based on your spring-context-support version:
If using Spring 3.1/3.2
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
p:shared="true"
p:config-location="classpath:ehcache.xml"/>
If using Spring 4.x
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
p:shared="false"
P:acceptExisting="true"
p:config-location="classpath:ehcache.xml"/>
Try naming both cacheManagers differently in ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
name="ehCacheManager1">
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
name="ehCacheManager2">

Annotation based ApplicationContext

I understand that the ApplicationContext can be annotation based in Spring 3.
Can anybody please share an example , so that I could refer the same.
Thanks in advance,
Vivek
EDIT - This is the XML configuration:
<context:annotation-config />
<context:component-scan base-package="com.test" />
<mvc:annotation-driven />
<bean id="dataSource" destroy-method="close" class=org.apache.commons.dbcp.BasicDataSource ">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/test" />
<property name="username" value="test" />
<property name="password" value="test" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="mapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.test.Mapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="dao" class="com.test.MapperDao">
<property name="mapper" ref="mapper" />
</bean>
<bean id="Controller" class="com.test.Controller" />
I have been through the Spring 3 Documentation and understood the #Configuration annotation.
So issue resolved :)

Resources