Wednesday, March 25, 2015

Solved: JPA persist cannot save anything to database and no exception

I am using Spring JPA to insert data into database. In the persistence.xml, I use JTA transaction type, instead of RESOURCE_LOCAL. This means we use JTA and container managed transactions. 

 <persistence-unit name="name-unit" transaction-type="JTA">  

During the development time, I had some difficulties to use persist to save data into database. Here are a few things I would like to share to  pay attention when we work on this.

1. Setup persistence.xml. The following is what I used. The highlighted ones were new added when the code didn't work.

 <?xml version="1.0" encoding="UTF-8" standalone="no"?>  
 <persistence xmlns="http://java.sun.com/xml/ns/persistence"  
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0"  
      xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">  
      <persistence-unit name="name-unit"           transaction-type="JTA">  
           <provider>org.hibernate.ejb.HibernatePersistence</provider>  
           <jta-data-source>java:/xxx/datasources/dsname</jta-data-source>  
           <class>xxx.model.Class</class>  
                 <exclude-unlisted-classes>false</exclude-unlisted-classes>  
           <properties>  
                <property name="connection.driver_class" value="com.ibm.db2.jcc.DB2Driver" />  
                <property name="hibernate.dialect" value="org.hibernate.dialect.DB2Dialect" />  
                <property name="hibernate.show_sql" value="true" />  
                <property name="hibernate.format_sql" value="true" />  
                <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />  
                <property name="hibernate.connection.charSet" value="UTF-8" />  
                <property name="hibernate.max_fetch_depth" value="5" />  
                <property name="hibernate.connection.clientProgramName" value="supsearch" />  
                <property name="hibernate.cache.use_second_level_cache" value="false" />  
                <property name="hibernate.cache.use_query_cache" value="false" />  
                <property name="hibernate.hbm2ddl.import_files_sql_extractor" value="org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor" />  
                <property name="hibernate.validator.apply_to_ddl" value="false" />  
                <property name="hibernate.validator.autoregister_listeners" value="false" />                      
                <property name="jboss.entity.manager.factory.jndi.name" value="java:/name-emf" />  
                <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform" />  
                <property name="hibernate.generate_statistics" value="true" />  
       </properties>  
      </persistence-unit>  
 </persistence>  


2. Setup Spring JTA Transaction Manager and other JTA information
Spring will automatically discover the underlying JTA implementation.
We need to add JTA Transaction Manager into applicationContext.xml, in my case it is called web-persistence.xml.


 <?xml version="1.0" encoding="UTF-8" standalone="no"?>  
 <beans xmlns="http://www.springframework.org/schema/beans"   
      xmlns:context="http://www.springframework.org/schema/context"   
      xmlns:jee="http://www.springframework.org/schema/jee"   
      xmlns:tx="http://www.springframework.org/schema/tx"  
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      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/jee   
           http://www.springframework.org/schema/jee/spring-jee.xsd       
           http://www.springframework.org/schema/tx   
           http://www.springframework.org/schema/tx/spring-tx.xsd">  
      <!-- Note: imported by SecurityConfig.java -->  
  <context:mbean-export/>  
      <jee:jndi-lookup id="entityManagerFactory" jndi-name="persistence/name-unit" expected-type="javax.persistence.EntityManagerFactory" />  
      <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">  
           <property name="persistenceUnits">  
                <map>          
                     <entry key="name-unit" value="persistence/name-unit" />  
                </map>  
           </property>  
           <property name="persistenceContexts">  
                <map>  
                     <entry key="name-unit" value="persistence/name-context"/>  
                </map>  
           </property>  
      </bean>  
      <bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">  
           <property name="entityManagerFactory" ref="entityManagerFactory" />  
      </bean>  
      <tx:annotation-driven/>       
      <tx:jta-transaction-manager/>  
 </beans>  

3. Injection via @PersistenceContext

The EntityManager itself is created by the container using the information in the persistence.xml, so to use it at runtime, we simply need to request it be injected into one of our components. We do this via @PersistenceContext.

@PersistenceContext should put into DAO impl. In my case it is called repository impl.

 @Repository  
 public class XxxxClassRepositoryImpl implements  
           XxxxClassRepository, Serializable {  
      private static final long serialVersionUID = 1L;  
      @PersistenceContext   
      private EntityManager emgr;  


4. Add @Transactional Annotation 

In the DAO impl layer and service impl layer (if you have), we need to add @Transcational annotation in. This annotation can be added in the class level and method level.

  @Repository   
  @Transactional  
  public class XxxxClassRepositoryImpl implements   
       XxxxClassRepository, Serializable {   
    private static final long serialVersionUID = 1L;   
    @PersistenceContext    
    private EntityManager emgr;   


If you want to learn how Spring transactional really work, I found this blog is very helpful.
http://blog.jhades.org/how-does-spring-transactional-really-work/



No comments:

Post a Comment