0
votes

I am in the process of slowly upgrading a large project from EJB entity beans to Spring Data JPA. The initial effort is using Spring Data 1.6.6, JPA 2.0, Spring Framework 3.2.14. I have some beans converted and working will with H2 database in unit tests.

Now I am trying to deploy to JBoss 5.2 and the data does not get committed to the database. I have an EntityListener and the PrePersist method gets called but the PostPersist does not. So somehow Hibernate has them as managed beans but they are never committed to the database. I tried adding @Transaction with different propagations but the entities are still not written to database. I am assuming that my configuration is somehow missing a connection of the entity manager to the transaction. I researched other postings but have not found any combination that works. Here is my configuration:

    <!-- Create default configuration for Hibernate -->
<bean id="hibernateJpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    <property name="databasePlatform" value="${hibernate.dialect:org.hibernate.dialect.Oracle10gDialect}"/>
    <property name="showSql" value="false"/>
</bean>

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="springbatch.repositoryDataSource" />
    <property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
            <prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</prop>
            <prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</prop>
            <prop key="hibernate.transaction.auto_close_session">true </prop>
            <prop key="hibernate.current_session_context_class">jta</prop>
            <prop key="hibernate.connection.release_mode">auto</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.format_sql">true</prop>
            <prop key="hibernate.transaction.jta.platform">org.hibernate.service.jta.platform.internal.JBossStandAloneJtaPlatform</prop>
        </props>
    </property>
    <property name="packagesToScan">
        <list>
            <value>com.*</value>
        </list>
    </property>
</bean>

<!-- Transaction Manager -->
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> 
    <property name="transactionManagerName" value="java:/TransactionManager" />
    <property name="userTransactionName" value="UserTransaction" />
    <property name="allowCustomIsolationLevels" value="true"/>
</bean>

<jpa:repositories base-package="com.*" factory-class="com.stoneriver.powersuite.persistence.repository.BaseRepositoryFactoryBean" />

<!-- bean post-processor for JPA annotations -->
<bean id="persistenceExceptionTranslationPostProcessor"
    class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

<!-- bean post-processor for JPA annotations -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>

Can anyone give me some recommendations?

Thanks

Here is the logging for saving 1 entity:

2018-03-25 16:45:49,826 DEBUG [org.springframework.transaction.jta.JtaTransactionManager] (http-0.0.0.0-8080-9) Participating in existing transaction
2018-03-25 16:45:49,828 TRACE [org.springframework.transaction.support.TransactionSynchronizationManager] (http-0.0.0.0-8080-9) Initializing transaction synchronization
2018-03-25 16:45:49,830 TRACE [org.springframework.transaction.interceptor.TransactionInterceptor] (http-0.0.0.0-8080-9) Getting transaction for [com.stoneriver.powersuite.persistence.repository.BaseRepositoryImpl.save]
2018-03-25 16:45:49,832 DEBUG [org.springframework.orm.jpa.EntityManagerFactoryUtils] (http-0.0.0.0-8080-9) Opening JPA EntityManager
2018-03-25 16:45:49,838 DEBUG [org.springframework.orm.jpa.EntityManagerFactoryUtils] (http-0.0.0.0-8080-9) Registering transaction synchronization for JPA EntityManager
2018-03-25 16:45:49,841 TRACE [org.springframework.transaction.support.TransactionSynchronizationManager] (http-0.0.0.0-8080-9) Bound value [org.springframework.orm.jpa.EntityManagerHolder@71f03e27] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@7bcd0210] to thread [http-0.0.0.0-8080-9]
2018-03-25 16:45:49,848 INFO  [com.stoneriver.powersuite.persistence.listeners.RecordIdEntityListener] (http-0.0.0.0-8080-9) onPrePersist : com.taliantsoftware.rulesengine.conditionevaluator.ejb.ExpressionBean .... id: 10032005
2018-03-25 16:45:49,923 INFO  [com.stoneriver.powersuite.persistence.repository.BaseRepositoryImpl] (http-0.0.0.0-8080-9) Saved ExpressionBean with Id : 10032005
2018-03-25 16:45:49,926 TRACE [org.springframework.transaction.interceptor.TransactionInterceptor] (http-0.0.0.0-8080-9) Completing transaction for [com.stoneriver.powersuite.persistence.repository.BaseRepositoryImpl.save]
2018-03-25 16:45:49,928 TRACE [org.springframework.transaction.jta.JtaTransactionManager] (http-0.0.0.0-8080-9) Triggering beforeCommit synchronization
2018-03-25 16:45:49,929 TRACE [org.springframework.transaction.jta.JtaTransactionManager] (http-0.0.0.0-8080-9) Triggering beforeCompletion synchronization
2018-03-25 16:45:49,931 TRACE [org.springframework.transaction.support.TransactionSynchronizationManager] (http-0.0.0.0-8080-9) Removed value [org.springframework.orm.jpa.EntityManagerHolder@71f03e27] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@7bcd0210] from thread [http-0.0.0.0-8080-9]
2018-03-25 16:45:49,933 DEBUG [org.springframework.orm.jpa.EntityManagerFactoryUtils] (http-0.0.0.0-8080-9) Closing JPA EntityManager
2018-03-25 16:45:49,935 TRACE [org.springframework.transaction.jta.JtaTransactionManager] (http-0.0.0.0-8080-9) Triggering afterCommit synchronization
2018-03-25 16:45:49,936 DEBUG [org.springframework.transaction.jta.JtaTransactionManager] (http-0.0.0.0-8080-9) Registering after-completion synchronization with existing JTA transaction
2018-03-25 16:45:49,938 TRACE [org.springframework.transaction.support.TransactionSynchronizationManager] (http-0.0.0.0-8080-9) Clearing transaction synchronization
2018-03-25 16:45:49,941 TRACE [org.springframework.transaction.support.TransactionSynchronizationManager] (http-0.0.0.0-8080-9) Removed value [org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$DefaultCrudMethodMetadata@a2d7c25] for key [public abstract java.lang.Object com.stoneriver.powersuite.persistence.repository.BaseRepository.save(java.lang.Object)] from thread [http-0.0.0.0-8080-9]
2
How do you test/know that the entities (don't) get written to the database?Jens Schauder
The current testing approach (will be updated when we get totally off of entity beans) uses cactus. So I am running a unit test through cactus. Does not use the Spring Unit Test Runner...from what I read, that is the piece that requires the @Rollback(false). So to confirm, I do not see the PostUpdate entity listener called and the data is not in the database. If I change from save() to saveAndFlush(), it is written out to the database. That approach complicates the conversion from EJB client code. So I would like to have the information written out on transaction commit.Mike Rother
I just reviewed the current code, and a stateless session bean (with transaction required) is in the call flow prior to the calls to the JPA RepositoryMike Rother

2 Answers

0
votes

Sounds like you are hitting a typical JPA challenge: JPA does almost nothing before a flush-event (which is also included in a commit). So you need to add some transaction management in your tests.

Probably the easiest way to do that is with the Spring Test Runner and if you want to keep the database state after the test @Rollback(false)

0
votes

After reading through the source code for hibernate for the version I was using, these changes solved the problems.

<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jtaDataSource" ref="springbatch.repositoryDataSource" />
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
<property name="jpaProperties">
    <props>
        <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
        <prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</prop>
        <prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</prop>
        <prop key="hibernate.transaction.auto_close_session">true </prop>
        <prop key="hibernate.current_session_context_class">jta</prop>
        <prop key="hibernate.connection.release_mode">auto</prop>
        <prop key="hibernate.show_sql">true</prop>
        <prop key="hibernate.format_sql">true</prop>
        <prop key="hibernate.transaction.jta.platform">org.hibernate.service.jta.platform.internal.JBossStandAloneJtaPlatform</prop>
    </props>
</property>
<property name="packagesToScan">
    <list>
        <value>com.*</value>
    </list>
</property>

specifically

<property name="jtaDataSource" ref="springbatch.repositoryDataSource" />

and

<prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</prop>