Announcement Announcement Module
Collapse
No announcement yet.
JPA(hibernate) and Spring Transaction Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • JPA(hibernate) and Spring Transaction

    I am using hibernate 3.6 (JPA interface) , Spring 3.0.3 , and the Spring JpaTransactionManager. Whenever I do a entityManager.find() I can see hibernate firing a SQL query but on persist I don't see a update or insert . Please find the library versions, code and my findings below. Any pointers would be highly appreciated.....

    thanks,
    Parag

    - Before a transactional method is called “TransactionSynchronizationManager.bindResource” sets the EntityManager (with an associated transaction ) as ThreadLocal. (stack 1)

    - “EntityManagerFactoryUtils.doGetTransactionalEntit yManager()” is called when a “entityManager.find/ createNamedQuery/persist ” is done from application code. (stack 2)

    - This in turn tries to get the transactional EntityManager from ThreadLocal and doesnot find it… (am not sure what removes it, and this seems to be the problem..) and creates a new EntityManager which does not have a transaction associated

    - when entityManager.persist() is called the insert is not done since there is not transaction associated with the EntityManager (stack 3)


    1. Stack before business method is called
    Code:
    TransactionSynchronizationManager.bindResource(Object, Object) line: 170    
    JpaTransactionManager.doBegin(Object, TransactionDefinition) line: 357             
    JpaTransactionManager(AbstractPlatformTransactionManager).getTransaction(TransactionDefinition) line: 371                
    TransactionInterceptor(TransactionAspectSupport).createTransactionIfNecessary(PlatformTransactionManager, TransactionAttribute, String) line: 316     
    TransactionInterceptor.invoke(MethodInvocation) line: 105
    2. Stack when EntityManager.find / createNamedQuery / is called

    Code:
    TransactionSynchronizationManager.getResource(Object) line: 136       
    EntityManagerFactoryUtils.doGetTransactionalEntityManager(EntityManagerFactory, Map) line: 167         
    SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(Object, Method, Object[]) line: 211        
    $Proxy144.find(Class, Object) line: not available                
    DataSourceDaoImpl.getProviderTypeById(int) line: not available              
    DataSourceDaoImpl.saveProviderType(DataProviderType) line: not available     
    DataSourceDaoImpl$$FastClassByCGLIB$$e55fce5f.invoke(int, Object, Object[]) line: not available          
    MethodProxy.invoke(Object, Object[]) line: 191               
    Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint() line: 688       
    Cglib2AopProxy$CglibMethodInvocation(ReflectiveMethodInvocation).proceed() line: 150         
    TransactionInterceptor.invoke(MethodInvocation) line: 110       
    Cglib2AopProxy$CglibMethodInvocation(ReflectiveMethodInvocation).proceed() line: 172         
    Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 621         
    DataSourceDaoImpl$$EnhancerByCGLIB$$335c347.saveProviderType(DataProviderType) line: not available        
    AssessmentUserFavoritesSetHandler.handleRequest(AssessmentUserFavoritesSetRequest) line: 40
    3. stack when entityManager.persist() is called.


    Code:
    EJB3PersistEventListener(AbstractSaveEventListener).performSaveOrReplicate(Object, EntityKey, EntityPersister, boolean, Object, EventSource, boolean) line: 263             
    EJB3PersistEventListener(AbstractSaveEventListener).performSave(Object, Serializable, EntityPersister, boolean, Object, EventSource, boolean) line: 203                
    EJB3PersistEventListener(AbstractSaveEventListener).saveWithGeneratedId(Object, String, Object, EventSource, boolean) line: 129               
    EJB3PersistEventListener.saveWithGeneratedId(Object, String, Object, EventSource, boolean) line: 69 
    EJB3PersistEventListener(DefaultPersistEventListener).entityIsTransient(PersistEvent, Map) line: 179    
    EJB3PersistEventListener(DefaultPersistEventListener).onPersist(PersistEvent, Map) line: 135   
    EJB3PersistEventListener(DefaultPersistEventListener).onPersist(PersistEvent) line: 61 
    SessionImpl.firePersist(PersistEvent) line: 808   
    SessionImpl.persist(String, Object) line: 782        
    SessionImpl.persist(Object) line: 786      
    EntityManagerImpl(AbstractEntityManagerImpl).persist(Object) line: 672            
    NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]        
    NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39    
    DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25            
    Method.invoke(Object, Object...) line: 597          
    ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(Object, Method, Object[]) line: 365                
    $Proxy179.persist(Object) line: not available       
    NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]        
    NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39    
    DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25            
    Method.invoke(Object, Object...) line: 597          
    SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(Object, Method, Object[]) line: 240        
    $Proxy144.persist(Object) line: not available       
    DataSourceDaoImpl.saveProviderType(DataProviderType) line: not available     
    DataSourceDaoImpl$$FastClassByCGLIB$$e55fce5f.invoke(int, Object, Object[]) line: not available          
    MethodProxy.invoke(Object, Object[]) line: 191               
    Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint() line: 688       
    Cglib2AopProxy$CglibMethodInvocation(ReflectiveMethodInvocation).proceed() line: 150         
    TransactionInterceptor.invoke(MethodInvocation) line: 110       
    Cglib2AopProxy$CglibMethodInvocation(ReflectiveMethodInvocation).proceed() line: 172         
    Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 621         
    DataSourceDaoImpl$$EnhancerByCGLIB$$335c347.saveProviderType(DataProviderType) line: not available        
    AssessmentUserFavoritesSetHandler.handleRequest(AssessmentUserFavoritesSetRequest) line: 40     
    AssessmentUserFavoritesSetHandler.handleRequest(APIRequest) line: 27

  • #2
    This is my code ...

    Code:
    public class AssessmentUserFavoritesSetHandler implements APIHandler<AssessmentUserFavoritesSetRequest , AssessmentUserFavoritesSetResponse> {
    
        @Inject
        public DataSourceDao dataSourceDao;
    
        @Override
        public AssessmentUserFavoritesSetResponse handleRequest(AssessmentUserFavoritesSetRequest request) {
    
            DataProviderType dataProviderType = new DataProviderType("DFM", "1.0", DriverType.MYSQL);
            dataSourceDao.saveProviderType(dataProviderType);
            return new AssessmentUserFavoritesSetResponse();
        }
    }
    DAO implementation ...

    Code:
    @Repository
    @Transactional
    public class DataSourceDaoImpl implements DataSourceDao {
    
            
        public EntityManager entityManager;    
        
       @PersistenceContext(name = "wfa-ds")
        public void setEntityManager(EntityManager entityManager) {
        	this.entityManager = entityManager;   
        }
        
        private void setUpdateTimeAndUser(BaseEntity be) {
            be.setUpdatedOn(new Date());
            //String userName = ctx.getCallerPrincipal() == null ? null : ctx.getCallerPrincipal().getName();
            String userName = "userName";
            be.setUpdatedBy(userName);
        }
        
        
        public void saveProviderType(DataProviderType dataProviderType) {
            DataProviderType dataProviderTypeFromDb = getProviderTypeById(dataProviderType.getId());
            if (dataProviderTypeFromDb != null) {
                setUpdateTimeAndUser(dataProviderType);
                dataProviderType.setPreCanned(false);
                
                entityManager.merge(dataProviderType);
                
            } else {
                dataProviderTypeFromDb = getProviderType(dataProviderType.getProductType(), dataProviderType.getProductVersion(), dataProviderType.getDriverType());
                if (dataProviderTypeFromDb != null) {
                    throw new WfaException("Can't save data source type: '" + dataProviderType.getProductType() + "'. \nA data source type with this name already exists");
                }
                setUpdateTimeAndUser(dataProviderType);
                dataProviderType.setPreCanned(false);
                
                entityManager.persist(dataProviderType);            
            }
        }
        
        
        @Override
        public DataProviderType getProviderTypeById(int id) {
        	
            return entityManager.find(DataProviderType.class, id);
        }
        
        
        private DataProviderType getProviderType(String productType, String productVersion, DriverType driverType) {
        	
            Query query = entityManager.createNamedQuery(DataProviderType.QUERY_PROVIDER_TYPE);
            query.setParameter("productType", productType);
            query.setParameter("productVersion", productVersion);
            query.setParameter("driverType", driverType);
    
            @SuppressWarnings({"unchecked"})
            List<DataProviderType> resultList = query.getResultList();
            if (resultList.size() > 0) {//should be only one, there is a unique constraint on these fields
                return resultList.get(0);
            } else {
                return null;
            }
        }
    }
    applicationContext.xml...

    Code:
    <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:util="http://www.springframework.org/schema/util"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:p="http://www.springframework.org/schema/p"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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
                            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
                            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
        >
    
    	<context:annotation-config />
        
    	<bean id="wfaDataSource" class="org.apache.commons.dbcp.BasicDataSource"  destroy-method="close" scope="singleton">      
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost/wfa"/>
            <property name="username" value="####"/>
            <property name="password" value="####"/>		
        </bean>
    
        <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" p:persistence-xml-location="classpath:META-INF/persistence.xml" >    	
    		<property name="jpaVendorAdapter">
    			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    				<property name="showSql" value="true" />
    			</bean>
    		 </property>		 
    		 <property name="dataSource" ref="wfaDataSource"/>
    		 <property name="loadTimeWeaver">
        	 	<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
      		 </property>		 		 	
    	</bean>
    	
         
        <bean id="jpaTransactionManager"  class="org.springframework.orm.jpa.JpaTransactionManager">
            <property name="entityManagerFactory" ref="entityManagerFactory"/>
            <property name="dataSource" ref="wfaDataSource"/>
        </bean>
        
        <tx:annotation-driven transaction-manager="jpaTransactionManager" proxy-target-class="true" />      
          
        <context:component-scan base-package="com.netapp.wfa.datasource.crud.impl" />
        
        <context:component-scan base-package="com.netapp.wfa.datasource.model" />   
    
    	<tx:annotation-driven transaction-manager="jpaTransactionManager" proxy-target-class="true"/>
    	    
        <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
    
    </beans>
    this is my persistence xml
    Code:
    <persistence xmlns="http://java.sun.com/xml/ns/persistence"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
                 version="1.0">
    
        <persistence-unit name="wfa-ds">
            <properties>
    			<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
    			<property name="hibernate.hbm2ddl.auto" value="update"/>
    			<property name="hibernate.show_sql" value="true"/>
            </properties>
        </persistence-unit>
    
    </persistence>
    I am using these libraries
    spring-tx\3.0.3.RELEASE
    spring-orm\3.0.3.RELEASE
    spring-core\3.0.3.RELEASE
    spring-jdbc\3.0.3.RELEASE
    hibernate-core\3.6.0
    hibernate-entitymanager\3.6.0
    org.apache\commons-dbcp\1.4
    Last edited by ppp2k1; Aug 23rd, 2011, 08:20 AM.

    Comment


    • #3
      1) remove context:annotation-config that is already implied by using component-scan
      2) You have 2 tx:annotation-driven elements
      3) Transactions should be defined on the service layer NOT the dao layer, your service method is the transactional boundary (in general)
      4) Why is your entity manager public shouldn't it be private (and I would put the @PersistenceContext annotation on the field and not on a setter method).

      What is in your persistence.xml?

      Comment


      • #4
        ok I have fixed 1, 2 and 4, I see the same issue. Here is my persistence.xml

        Code:
        <persistence xmlns="http://java.sun.com/xml/ns/persistence"
                     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                     xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
                     version="1.0">
        
            <persistence-unit name="wfa-ds">
                <properties>
        			<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
        			<property name="hibernate.hbm2ddl.auto" value="update"/>
        			<property name="hibernate.show_sql" value="true"/>
                </properties>
            </persistence-unit>
        
        </persistence>

        Comment


        • #5
          I have fixed 1,2,4 . I see the same issue. this is my persistence.xml
          Code:
          <persistence xmlns="http://java.sun.com/xml/ns/persistence"
                       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                       xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
                       version="1.0">
          
              <persistence-unit name="wfa-ds">
                  <properties>
          			<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
          			<property name="hibernate.hbm2ddl.auto" value="update"/>
          			<property name="hibernate.show_sql" value="true"/>
                  </properties>
              </persistence-unit>
          
          </persistence>

          Comment


          • #6
            figured this one out... the org.springframework.transaction.jar was getting deployed at 2 places and being loaded by 2 different Class Loaders (jetty and system, I think) . This was causing the ThreadLocals in the Spring TransactionSynchronizationManager to disappear mysteriously and then reappear again. Removed the jar from one of the locations and the code above works !!! :-)

            Comment


            • #7
              Hi,
              I am facing the similar problem. Following the approach given at http://www.techbrainwave.com/?p=725
              This works fine when i execute it through standalone program main method, but when deployed at tomcat it does not persist data. entitymanager.find() works properly. persist() method does not save data to database as well as doesn't through any error. When tried to check EntityManager.getDelegate() it also returns null.

              Any Clue?

              Comment

              Working...
              X