Spring JavaFX #Transactional entitymanager is closed - spring

i'm stuck on a Transactional Problem using Spring #Transactional with a JavaFX application, all my beans, and graphical components are managed by spring.
I initialize my appusing #PostConstruct on my Controllers.
In the PostConstruct, all my daos are working perfectly but when i invoke a service to save something by pressing a JavaFX button i got this exception.
Caused by: org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is java.lang.IllegalStateException: EntityManagerFactory is closed
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:431)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:463)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:276)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy48.saveGame(Unknown Source)
at dev.debizis.mtggui.desktop.controller.TemplateEditorController.handleSaveGameAction(TemplateEditorController.java:362)
... 68 more
Caused by: java.lang.IllegalStateException: EntityManagerFactory is closed
at org.hibernate.jpa.internal.EntityManagerFactoryImpl.validateNotClosed(EntityManagerFactoryImpl.java:388)
at org.hibernate.jpa.internal.EntityManagerFactoryImpl.internalCreateEntityManager(EntityManagerFactoryImpl.java:342)
at org.hibernate.jpa.internal.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:313)
at org.springframework.orm.jpa.JpaTransactionManager.createEntityManagerForTransaction(JpaTransactionManager.java:449)
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:369)
... 76 more
Does anyone know why the entityManager does not open for transaction using #Transactonal on a method ?
My hibernate beans config :
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<!-- the property configurer for the datasource -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>jdbc.properties</value>
</list>
</property>
<property name="ignoreUnresolvablePlaceholders" value="true" />
</bean>
<!-- the DataSource (parameterized for configuration via a PropertyPlaceHolderConfigurer) -->
<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="${h2.jdbc.driverClassName}" />
<property name="url" value="${h2.jdbc.url}" />
<property name="username" value="${h2.jdbc.username}" />
<property name="password" value="${h2.jdbc.password}" />
</bean>
<!-- Hibernate SessionFactory Definition Debug -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.cardassiel.dao.entity" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.connection.autocommit">false</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
<prop key="hibernate.bytecode.use_reflection_optimizer">true</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</prop>
<!-- <prop key="hibernate.enable_lazy_load_no_trans">true</prop> -->
</props>
</property>
</bean>
<!-- Hibernate Transaction Manager Definition -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
My services context
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<import resource="classpath*:dao-context.xml" />
<import resource="classpath*:common-context.xml" />
<context:component-scan base-package="com.cardassiel.core.service" />
<context:component-scan base-package="com.cardassiel.core.mapper" />
<!-- hibernate transaction by annotations -->
<tx:annotation-driven transaction-manager="transactionManager" />
My save method :
/** {#inheritDoc} */
#Override
#Transactional
public final Long saveGame(final GameDTO game) {
LOGGER.debug("saveGame : name = {}", game.getName());
return gameDao.saveOrUpdate(mapper.map(game, Game.class));
}
My Dao method :
/** {#inheritDoc}*/
#SuppressWarnings("unchecked")
#Override
public final P saveOrUpdate(final T o) {
if (entityManager.getEntityManagerFactory().getPersistenceUnitUtil().getIdentifier(o) == null) {
entityManager.persist(o);
} else {
entityManager.merge(o);
}
return (P) entityManager.getEntityManagerFactory().getPersistenceUnitUtil().getIdentifier(o);
}
Thanks by advance.

By reading logs, i've understood what's happened.
A thread was closing the applicationContext, and implicitely all singletons beans including the entityManagerFactory !
The entityManagerFactory can only be open once per PersistenceUnit lifecycle.
When the Transaction try to open an entityManager with a closed factory, it throw an exception.

Related

Error when setting 2 DataBases without bean annotation using SpringData

I have problem when i try configure 2 dataSources in my xml applicationContext.xml.
The examples i find reffer using bean annotation for configuration.
i need configuration in xml in my actual architecture.
I saw tutorial:
http://www.baeldung.com/spring-data-jpa-multiple-databases
and
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-two-datasources
But i don't solve my problem, the method used in this Spring page use annotation. I can't use annotation, my configuration is there in xml.
When i try apply seconf datasource has error.
Before add second datasource, work's fine!
When add second datasource don't work.
My applicationContext.xml :
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-4.2.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"
default-autowire="byName" default-lazy-init="true">
<context:annotation-config />
<context:component-scan base-package="br.com.myProject" />
<jpa:repositories base-package="br.com.myProject.ged.repository"/>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean" scope="singleton">
<property name="jndiName" value="java:jboss/datasources/sgedDS" />
<property name="resourceRef" value="true" />
</bean>
<bean id="dataSourceNurer" class="org.springframework.jndi.JndiObjectFactoryBean" scope="singleton">
<property name="jndiName" value="java:jboss/datasources/nurerDS" />
<property name="resourceRef" value="true" />
</bean>
<!-- ************** ENTITY MANAGER SGED ******************** -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="packagesToScan" value="br.com.myProject.ged.entity" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">false</prop>
</props>
</property>
</bean>
<!-- ************** ENTITY NURER NURER ******************** -->
<bean id="entityManagerFactoryNurer" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="packagesToScan" value="br.com.myProject.ged.entity" />
<property name="dataSource" ref="dataSourceNurer" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">false</prop>
</props>
</property>
</bean>
<!-- ******** SGED ******** -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- ******** NURER ******** -->
<bean id="transactionManagerNurer" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryNurer" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" /> <!-- SGED -->
<tx:annotation-driven transaction-manager="transactionManagerNurer" /> <!-- NURER -->
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="view">
<bean class="br.com.myProject.ged.spring.SpringViewScope" />
</entry>
</map>
</property>
</bean>
</beans>
My Bean Service layer:
#Transactional (transactionManager = "transactionManager2")
public List<DataBase2Entity> getAll(){
return nurerSituacaoIdrRepository.findAll();
// return new ArrayList<DataBase2Entity>();
}
#Transactional (transactionManager = "transactionManager")
public List<DataBaseEntity> getAll(){
return nurerSituacaoIdrRepository.findAll();
// return new ArrayList<DataBaseEntity>();
}
My BaseDao.java
public abstract class BaseDao<T> {
private Class<T> entityClass;
#PersistenceContext(unitName = "entityManagerFactory")
private EntityManager em;
#PersistenceContext(unitName = "entityManagerFactoryNurer")
private EntityManager emNurer;
#SuppressWarnings("unchecked")
public BaseDao() {
this.entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
...
UPDATE : 02/10/2017
ERROR execution time:
Error creating bean with name 'entityManagerFactory' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Error setting property values
I use same entityManagerFactory or create another entityManagerFactory (see BaseDao.java).
This seems to be an issue with XML.
I see there is a . (dot) at the end on line no #105
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>.
Remove the dot and try again.

Spring+JPA+Hibernate multiple databases

I am trying to connect to two databases with Spring and JPA. I am already connected to one database(sql server 2012), and I need to connect to another without changing too much stuff. I have app-context-dao.xml file which holds my hibernate and JPA configuration:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<aop:aspectj-autoproxy proxy-target-class="false" />
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/SQLCMS" expected-type="javax.sql.DataSource" />
<jee:jndi-lookup id="dataSourceOracle" jndi-name="jdbc/razmjenskaDBSQL" expected-type="javax.sql.DataSource" />
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="hr.akd.cms.*" />
<property name="persistenceUnitName" value="caPersistenceUnit" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="org.hibernate.dialect.SQLServer2012Dialect" />
<property name="showSql" value="false" />
</bean>
</property>
<!-- ..................
Initialize additional Hibernate JPA related properties
if required
.................. -->
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
</bean>
<bean id="entityManagerFactoryOracle"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSourceOracle" />
<property name="persistenceUnitName" value="userPersistenceUnit" />
<property name="packagesToScan" value="hr.akd.cms.*" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="org.hibernate.dialect.SQLServer2012Dialect" />
<property name="showSql" value="false" />
</bean>
</property>
<!-- ..................
Initialize additional Hibernate JPA related properties
if required
.................. -->
<property name="jpaProperties">
<props>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
</bean>
<!-- .................. Transaction manager setup .................. -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="transactionManagerOracle" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryOracle" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- .................. Spring data - declare base packages for scanning,
all classes extending from data repositories will be available for autowire
.................. -->
<jpa:repositories base-package="hr.akd.cms.repository"
factory-class="hr.akd.cms.repository.impl.CMSCustomRepositoryFactoryBean" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
<property name="defaultPersistenceUnitName" value="caPersistenceUnit"/>
</bean>
I added entityManagerFactoryOracle, dataSourceOracle jndi transactionManagerOracle for my second database. When I start my app I got this
Injection of persistence dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single bean but found 2: entityManagerFactory,entityManagerFactoryOracle
My factory bean looks like this:
public class CMSCustomRepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable>
extends JpaRepositoryFactoryBean<R, T, I> {
#SuppressWarnings("rawtypes")
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new CMSSearchFactoryFactory(entityManager);
}
private static class CMSSearchFactoryFactory<T, I extends Serializable> extends JpaRepositoryFactory {
private EntityManager entityManager;
public CMSSearchFactoryFactory(EntityManager entityManager) {
super(entityManager);
this.entityManager = entityManager;
}
#SuppressWarnings("unchecked")
protected Object getTargetRepository(RepositoryMetadata metadata) {
return new CMSCustomRepositoryImpl<T, I>((Class<T>) metadata.getDomainType(), entityManager);
}
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
// The RepositoryMetadata can be safely ignored, it is used by the
// JpaRepositoryFactory
// to check for QueryDslJpaRepository's which is out of scope.
return CMSCustomRepository.class;
}
}
You must make one of the dataSource and entityManagerFactory primary . primary = "true"
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
primary = "true">

No bean named 'entityManagerFactory' is defiend, bean reference issue

I am using spring-framework 4.0.2.RELEASE and hibernate-3.6.4.Final.
This spring data jpa configuration gives me an error:
No bean named 'entityManagerFactory' is defiend.
However I found that if I change bean name emf to entityManagerFactory then, there is no problem.
Can somebody explain why the bean reference does not work here?
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<!-- http://drypot.com/post/95?p=6 spring + hibernate: with JPA -->
<tx:annotation-driven />
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="emf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:packagesToScan="${entitymanager.packagesToScan}" >
<property name="dataSource" ref="dataSource" />
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<!-- validate | update | create | create-drop -->
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<!--prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop-->
<!-- hibernate ehcache
http://stackoverflow.com/questions/5270998/spring-hibernate-ehcache
-->
<prop key="hibernate.cache.provider_class">${hibernate.cache.provider_class}</prop>
<prop key="hibernate.cache.factory_class">${hibernate.cache.factory_class}</prop>
</props>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
</beans>
When working with Spring Data JPA it, by default, looks for a bean named entityManagerFactory. This is the default for both the xml namespace based configuration (<jpa:repositories />) and for the java bases configuration (#EnableJpaRepositories).
If you have a bean with another name you will have to make that clear to Spring Data JPA so that it can select the proper EntityManagerFactory to use.
<task:repositories entity-manager-factory-ref="emf" />
or java config
#EnableJpaRepositories(entityManagerFactoryRef="emf")
Links
Spring Data JPA reference guide
#EnableJpaRepositories javadoc
Try injecting your EntityManagerFactory specifing your bean's name like this:
#Autowired
#Qualifier(value = "emf")
private EntityManagerFactory entityManagerFactory;

SessionFactory is null

I'm using Spring with Hibernate and originally set up my project with a hibernate xml config, which resulted in performance issues and seemed like it was the wrong way to do it. I'm now trying to inject my SessionFactory, starting with 1 dao, but get a null pointer exception where sessionFactory.getCurrentSession() is called. I think my code looks like the examples I've seen. I'm stumped. I also tried not using resource and injecting the sessionFactory into the dao in the application context instead. Same result.
ApplicationContext.xml
<context:component-scan base-package="path.to.base">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingDirectoryLocations">
<list>
<value>classpath*:/path/to/mapping/files</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
myDAO
#Repository
public class myDAO {
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory(){
return sessionFactory;
}
#Resource(name="sessionFactory")
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public myDAO() {
}
#SuppressWarnings("unchecked")
#Transactional(readOnly=true)
public List<Things> getAllThings() {
return sessionFactory.getCurrentSession().createCriteria(EvalMasterEvaluationType.class)
.add(Restrictions.eq("active", "Y")).addOrder(Order.desc("createDtTm")).list();
}
}
Spring 3.2.1, Hibernate 3.6.10
I got it working, though I'm not sure which modification solved the problem. SRT_KP might be right after all about the datasource since I added some properties to it (maxactive, maxidle, validationquery). I switched to LocalSessionFactoryBean since I'm using xml mappings and added the mapping file suffix to the mappingLocations property. I also moved #Transactional to the service layer where it belongs.
Here's what I ended up with:
<?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"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<context:property-placeholder location="classpath*:WEB-INF/*.properties"/>
<context:component-scan base-package="org.base.to.scan">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="oraDataSource" />
<property name="mappingLocations" value="classpath*:org/path/to/mapping/files/*.hbm.xml" />
</bean>
<bean id="oraDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="maxActive" value="10" />
<property name="maxIdle" value="5" />
<property name="validationQuery" value="SELECT 'x' FROM dual" />
</bean>
<tx:annotation-driven/>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
BTW great tutorial: http://www.byteslounge.com/tutorials/spring-with-hibernate-persistence-and-transactions-example

Changing datasource connection url runtime

I am working on a project which uses spring + hibernate + mysql and c3p0 for connection pooling.
Currently the properties for the connection pool are loaded via properties defined outside the src. (eg: ${db_uname})
Everything starts fine when we create the spring bean.
It might so happen that the database to which we have connected is inaccessible for some reason, and we would like to switch hosts.
Need to implement a call back, where it is supposed to connect to the new host and re-initialize the pool
Any pointers on how to override the existing data source / connection pool gracefully would be of great help.
Here is how my spring config file looks like
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<!-- Component scans -->
<import resource="component-scans-1.xml" />
<import resource="component-scans-2.xml" />
<util:properties id="serviceManagerProperties"
location="classpath:servicemanagers.properties" />
<!-- Properties file -->
<context:property-placeholder location="classpath:database.config.properties,classpath:framework.properties" />
<!-- context:annotation-config / -->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<context:mbean-server id="mbeanServer" />
<context:mbean-export server="mbeanServer" default-domain="a.b.c" />
<bean id="cacheManager" factory-method="getInstance"
class="net.sf.ehcache.CacheManager" />
<bean class="net.sf.ehcache.management.ManagementService" init-method="init">
<constructor-arg ref="cacheManager" />
<constructor-arg ref="mbeanServer" />
<constructor-arg value="false" />
<constructor-arg value="false" />
<constructor-arg value="false" />
<constructor-arg value="true" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaAdapter" />
<property name="persistenceXmlLocation" value="classpath*:META-INF/framework-persistence.xml" />
<property name="persistenceUnitName" value="PU-NAME" />
<property name="jpaProperties">
<props>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop>
<prop key="hibernate.cache.use_second_level_cache">${hibernate.cache.use_second_level_cache}</prop>
<prop key="hibernate.cache.region.factory_class">
org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
</prop>
<prop key="hibernate.ejb.cfgfile">hibernate.cfg.xml</prop>
<prop key="hibernate.generate_statistics">true</prop>
<!-- CONNECTION SETTINGS -->
<prop key="hibernate.connection.driver_class">
com.mysql.jdbc.Driver
</prop>
<prop key="hibernate.connection.url">
jdbc:mysql://${dbhost}/${dbschema}?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8
</prop>
<prop key="hibernate.connection.username">${dbuser}</prop>
<prop key="hibernate.connection.password">${dbpass}</prop>
<!-- CONNECTION POOLING -->
<prop key="hibernate.connection.provider_class">
org.hibernate.connection.C3P0ConnectionProvider
</prop>
<prop key="hibernate.c3p0.maxPoolSize">${hibernate.c3p0.maxSize}</prop>
<prop key="hibernate.c3p0.minPoolSize">${hibernate.c3p0.minSize}</prop>
<prop key="hibernate.c3p0.acquireIncrement">${hibernate.c3p0.acquireIncrement}</prop>
<prop key="hibernate.c3p0.idleConnectionTestPeriod">${hibernate.c3p0.idleTestPeriod}</prop>
<prop key="hibernate.c3p0.maxStatements">${hibernate.c3p0.maxStatements}</prop>
<prop key="hibernate.c3p0.timeout">${hibernate.c3p0.timeout}</prop>
</props>
</property>
</bean>
<bean id="jpaAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
Assuming the database schema is right, lets say i get the database credentials and the host information in the event, i need to 're-set' the connection pool.
AbstractRoutingDataSource is a good choice.
Xml or annotation used like this:
<bean id="ds1" class="..c3p0.DataSource">
...
</bean>
<bean id="ds2" class="..c3p0.DataSource">
...
</bean>
<bean id="dataSource" class="..xxx.RoutingDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="ds1" value-ref="ds1"/>
<entry key="ds2" value-ref="ds2"/>
</map>
</property>
<property name="defaultTargetDataSource" ref="ds1"/>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
...
</bean>
Then build a class to determine current datasoruce.
public class RoutingDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<String> holder = new ThreadLocal<String>();
protected Object determineCurrentLookupKey()
{
return holder.get();
}
public static void clear(){
holder.remove();
}
public static void setDataSourceKey(String key){
holder.set(key);
}
}
By the way, the 'try-finally' statement is boring!
try{
RoutingDataSource.setDataSourceKey("ds1");
myDao.doXXX();
}finally{
RoutingDataSource.clear();
}
<beans:bean id="dataSource"
class="org.springframework.aop.framework.ProxyFactoryBean">
<beans:property name="targetSource" ref="swappableDataSource" />
</beans:bean>
<beans:bean id="dummyDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close" />
<beans:bean name="swappableDataSource"
class="org.springframework.aop.target.HotSwappableTargetSource">
<beans:constructor-arg ref="dummyDataSource" />
</beans:bean>
and some where in your code you can do this.
#Autowired
HotSwappableTargetSource swapable;
public void changeDatasource() throws Exception
{
swapable.swap(createNewSource();
}
ComboPooledDataSource createNewSource() throws Exception {
ComboPooledDataSource ds2 = new ComboPooledDataSource();
ds2.setJdbcUrl(url);
ds2.setDriverClass(driver);
ds2.setUser(username);
ds2.setPassword(password);
return ds2;
}
If you are asking for multiple databases connections ..it is possible with hibernate by creating multiple hibernate.cfg.file 's which is some what inappropriate
By following line you can acheive that .
SessionFactory sf = new Configuration().configure("somename.cfg.xml").buildSessionFactory();
When your primary connection not established you have load another hibernate configuration ...otherwise is wont possible .

Resources