In order to work around Hibernate bug HHH-2763, I'm trying to update my app from Hibernate 3 to Hibernate 4. It seemed to have gone smoothly until I realized that while my application can read data, it never seems to do inserts or updates. I turned on SQL logging: under Hibernate 3, there are inserts and updates. Under Hibernate 4, there are no inserts and updates.
We were doing explicit flushes in Hibernate 3 by overriding the OpenSessionInViewFilter class' closeSession method as follows:
public void closeSession(Session session, SessionFactory sessionFactory) {
session.flush();
super.closeSession(session, sessionFactory);
}
But in Hibernate 4, this is no longer an option because that method no longer exists.
My Hibernate 4 configuration for the Session Factory and Transaction Manager follows:
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.default_schema">${oracle.default_schema}</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.generate_statistics">false</prop>
<prop key="hibernate.show_sql">${hibernate.showSql}</prop>
<prop key="hibernate.use_sql_comments">true</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
<property name="mappingResources">
<list> . . . </list>
</property>
<property name="annotatedClasses">
<list> . . . </list>
</property>
</bean>
<!-- Configure transaction management, enabling #Transactional annotations -->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
<property name="nestedTransactionAllowed" value="true" />
</bean>
(Edit) And here's the configuration of the OpenSessionInViewFilter:
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>
org.springframework.orm.hibernate4.support.OpenSessionInViewFilter
</filter-class>
<init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>sessionFactory</param-value>
</init-param>
</filter>
My guess is that it's not flushing and committing. But why?
what do you mean by "But in Hibernate 4, this is no longer an option because that method no longer exists"?
spring comes with a OpenSessionInViewFilter for hibernate 4, which is:
org.springframework.orm.hibernate4.support.OpenSessionInViewFilter
are you still using?
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
try the new OpenSessionInViewFilter for hibernate 4
edit...
You do not have to flush the session manually, transcation manager will take care of it, as the javadoc of hibernate4 OpenSessionInViewFilter says:
The active transaction manager will temporarily change the flush mode
to FlushMode.AUTO during a read-write transaction, with the flush
mode reset to FlushMode.NEVER at the end of each transaction.
you can change you log level to TRACE, and check the console to make sure flush mode is set to AUTO:
... setting flush mode to: AUTO
or can you post your save/update code fragment?
Related
We have a spring-based web app which uses spring-data-jpa and openjpa with PostgreSQL DB. The EntityManager settings as below.
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter" />
</property>
<property name="persistenceUnitName" value="PersistenceUnit" />
<property name="jpaProperties">
<props>
<prop key="openjpa.ConnectionURL">jdbc:postgresql://${db.host}:${db.port}/${db.database}</prop>
<prop key="openjpa.ConnectionUserName">${db.username}</prop>
<prop key="openjpa.ConnectionPassword">${db.password}</prop>
<prop key="openjpa.ConnectionDriverName">org.postgresql.Driver</prop>
</props>
</property>
</bean>
As we have given the jpaProperties and org.postgreql.Drive only, the web app is running on tomcat8. What is the default connection pool will be used for this case?
org.postgresql.ds.PGPoolingDataSource
org.apache.commons.dbcp.BasicDataSource
com.mchange.v2.c3p0.ComboPooledDataSource
org.apache.tomcat.jdbc.pool
If we want to give a dataSource bean in this case, which connection pool is the best practice?
I've been trying to wrap my head around this issue all day.
Currently our project has setup JPATransactionManager through a Spring Application Context to take care of our various session transactions with the use of #Transactional on all services that take care of persistence and deletions (DAO usage).
Changing over from Hibernate 3 to 5, we wanted to remove our use of a custom audit interceptor and move onto using Hibernate Envers. I have annotated all my classes properly and have the tables being created, but once it actually gets to a point of insertion, the listener throws an error in which it can't find the current transaction given by JPA:
org.hibernate.envers.exception.AuditException: Unable to create revision because of non-active transaction
at org.hibernate.envers.event.spi.BaseEnversEventListener.checkIfTransactionInProgress(BaseEnversEventListener.java:132)
at org.hibernate.envers.event.spi.EnversPostInsertEventListenerImpl.onPostInsert(EnversPostInsertEventListenerImpl.java:34)
at org.hibernate.action.internal.EntityIdentityInsertAction.postInsert(EntityIdentityInsertAction.java:156)
at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:102)
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:597)
at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:232)
at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:213)
at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:256)
at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:318)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:275)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:182)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:113)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:192)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:177)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:97)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:651)
at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:643)
at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:638)
Looking inside the code, it seems that it's basing the transaction status off it's default value of INACTIVE meaning that it's not hooking into the transaction properly. I know that Hibernate Envers also automatically pushes the listeners into hibernate with recent versions so I don't know if this may also be a source of the issue.
I know that its been documented to work with HibernateTransactionManager but we wish to step away from using that in favor of hooking up our transactions and sessions solely via Spring making things easier so it may also be the need of finding an alternative to envers. Does anyone have any advice or solutions to this problem? Or also hit this issue?
ApplicationContext.xml
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="dataSource" ref=“dataSource" />
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="net.sourceforge.jtds.jdbcx.JtdsDataSource" />
<property name="url" value="jdbc:jtds:sqlserver://.." />
<property name="username" value=“..." />
<property name="password" value=“..." />
</bean>
<bean id="hibernateProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location">
<value>classpath:hibernate.properties</value>
</property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="hibernateProperties">
<ref bean="hibernateProperties" />
</property>
</bean>
<bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="transactionAttributes">
<props>
<prop key="find*">PROPAGATION_SUPPORTS,readOnly
</prop>
<prop key="load*">PROPAGATION_SUPPORTS,readOnly
</prop>
<prop key="make*">PROPAGATION_REQUIRED</prop>
<prop key="add*">PROPAGATION_REQUIRED</prop>
<prop key="refresh">PROPAGATION_SUPPORTS</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_SUPPORTS,readOnly
</prop>
</props>
</property>
</bean>
<bean id="PROPAGATION_REQUIRED" class="org.apache.camel.spring.spi.SpringTransactionPolicy">
<property name="transactionManager" ref="transactionManager" />
</bean>
hibernate.properties
#hibernate.hbm2ddl.auto=update
hibernate.show_sql=true
hibernate.connection.datasource=java\:comp/env/datasource
#hibernate.connection.provider_class=org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl
hibernate.connection.provider_class=org.hibernate.connection.DatasourceConnectionProvider
hibernate.cache.use_second_level_cache=true
hibernate.cache.use_query_cache=true
#hibernate.generate_statistics=true
hibernate.cache.use_structured_entries=true
hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory
hibernate.id.new_generator_mappings=false
hibernate.dialect=org.hibernate.dialect.SQLServer2008Dialect
hibernate.listeners.envers.autoRegister=false
org.hibernate.envers.track_entities_changed_in_revision=false
org.hibernate.envers.audit_table_prefix=AUD_
org.hibernate.envers.audit_table_suffix=
My DAOs are hooked up using the txProxyTemplate like so
<bean id="objectDAO" parent="txProxyTemplate">
<property name="target">
<bean
class="path.to.objectDAOImpl">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
</property>
</bean>
All my services that use the various DAOs are simply hooked up using the #Transactional annotation where we want to have transactions. I've been able to see through trace that my transactions are succeeding in completing and rolling back as well when there are errors. Once I added envers into the mix, the auditing can't find the transaction to join. There must be something I'm missing but I'm not sure what it is.
I don't believe you need to define a txProxyTemplate bean nor a SpringTransactionPolicy from my experience. This functionality has since been superseded with the <tx:/> tags and the use of the #Transactional annotation.
You just need to make sure a JpaTransactionManager has been created and associated as the transactionManager associated with the <tx:annotation-driven/> tag.
I have some issues after changing my backend from Hibernate to JPA (+Hibernate). I am using Websphere and container transaction management through org.springframework.transaction.jta.WebSphereUowTransactionManager. Some operations don't behave as expected:
DELETE OPERATION: If I don't flush the EntityManager manually it won't issue the delete, nothing happens actually.
#Transactional
#Override
public void deleteApplication(Integer appId) {
Application app = appDAO.findOne(appId);
//em.flush(); to force the flush(), otherwise it doesn't do anything
appDAO.delete(app);
}
INSERT WITH CASCADE OPERATION: The Application entity has a N:M relation with Attribute. I try to persist an Application with some Attribute added to its Application.attributes List. Right after the appDAO.save() I see a insert into Application sentence. However, there are never any inserts for the cascaded Attributes into the join table. Again, I need to manually flush() the em to issue de sql statements left.
#Transactional
#Override
public Application createApplication(Application application) {
appDAO.save(application);
//em.flush(); Needed to force the cascade into the join table
return application
}
I have tried changing the transactionManager for a non-container-managed one (org.springframework.orm.jpa.JpaTransactionManager) and it works perfectly without needing to use manual flush.
I am not using the persistence.xml file, following the approach introduced in Spring 3.1 (jtaDataSource + packagesToScan). However I have also tried with the traditional config with a persistence.xml file and I experienced the same wrong behaviour.
¿Any suggestions?
My setup:
<bean id="mainEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="mainPersistenceUnit"/>
<property name="jtaDataSource" ref="mainDataSource"/>
<property name="packagesToScan" ref="packages-mainEntityManagerFactory"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.WebSphereExtendedJTATransactionLookup</prop>
<prop key="hibernate.current_session_context_class">jta</prop>
<prop key="hibernate.transaction.flush_before_completion">true</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.transaction.factory_class">org.hibernate.transaction.CMTTransactionFactory</prop>
</props>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
</bean>
<tx:annotation-driven order="0" />
<!-- Drives transactions using local JPA APIs -->
<bean name="transactionManager" class="org.springframework.transaction.jta.WebSphereUowTransactionManager"/>
In case someone has the same problem. The solution comes down to using
<prop key="hibernate.transaction.factory_class">org.hibernate.ejb.transaction.JoinableCMTTransactionFactory</prop>
instead of
<prop key="hibernate.transaction.factory_class">org.hibernate.transaction.CMTTransactionFactory</prop>
I've read several topics but still don't understand. I have a spring mvc application that use hibernate on a DAO layer. The sessionFactory and transaction manager was configured in a standard way, service layer use `#Transaction` Also I use `OpenSessionInViewFilter`. I know that this filter set session flush mode to NEVER but then tx manager set it to AUTO for each tx and return it back once tx is commited. Also I get session as `sessionFactory.getCurrentSession()`.
My problem is with the non-read-only methods. Objects do not appears in the database after method is finished. Only after I explicitly call session.flush() the session state synchronized with the DB. As for me it's not a normal way. I think there is should be a property for tx manager or maybe sessionFactory or another bean that make a auto commit for non-read-only methods.
So, why FlushMode.AUTO may not work? Is it normal to call session.flush() manually in each non-read-only methods?
<bean name="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
p:dataSource-ref="aimsDataSource">
<property name="packagesToScan">
<list>
<value>net.adaptiveservices.aims.rc.model</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.NoCacheProvider</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop> <!--TODO Remove in production-->
</props>
</property>
</bean>
<bean name="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory"/>
Due to some GAE limitations, I cannot use the Spring session factory.
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="annotatedClasses">
<list>
<value>it.trew.prove.model.beans.Scadenza</value>
<value>it.trew.prove.model.beans.Fornitore</value>
<value>it.trew.prove.model.beans.Societa</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">create</prop>
<!-- <prop key="hibernate.hbm2ddl.import_files">/setup.sql</prop> -->
</props>
</property>
</bean>
See my other question if interested in it: Spring Autowiring stopped working on GAE
Now I want to create a session factory without org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean
How can I configure the pure session factory bean, using only hibernate stuff?
Why are you wanting to use hibernate with GAE? Are you using CloudSQL or the datastore? AppEngine isn't really meant for hibernate type stuff... you're much better off looking at using Objectify or Twig, or if you want an ORM solution, JDO.