6

I know that my problem is a common problem, but I've checked a lot of questions here, checked Spring documentation and I really don't know what I am doing wrong. My problem: I've got a Spring WebFlow project using JPA (implementation: OpenJPA + MySQL database). I use Spring ORM to inject EntityManager (by @PersistenceContext annotation) to my simple RegisterDAO. I have configured GlassFishs (which I am using) connection pools for using MySQL and everything works - I can work with my database, but when I am persisting something - nothing happens (data are not persist to database). I know that problem is with transactional context which I use. I read the documentation of Spring Transaction Management and follow the configuration steps in this documentation. This is my applicationContext.xml:

<?xml version="1.0" encoding="windows-1250"?>
<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:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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
       http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
       http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd">

    <jee:jndi-lookup id="entityManagerFactory" jndi-name="myPersistenceUnit"/> 
    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>

    <bean id="registerDaoImpl" class="umk.dumont.db.dao.RegisterDAO" />
    <bean id="registerModel" class="umk.dumont.models.RegisterFormModel">
        <property name="registerDAO" ref="registerDaoImpl" />
    </bean>


  <tx:advice id="txAdvice">
    <tx:attributes>
      <tx:method name="*" />
    </tx:attributes>
  </tx:advice> 

  <aop:config>
    <aop:pointcut id="registerModelOperation" expression="execution(* umk.dumont.models.RegisterFormModel.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="registerModelOperation"/>
  </aop:config>

  <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" />


</beans>

As you can see I am injecting RegisterDAO into my RegisterFormModel, which contains my business logic for validating register form data and eventually adding user to database. Validating works fine, the problem occurs when I am trying to add new user. Here is the code:

package umk.dumont.models;

...

public class RegisterFormModel implements Serializable {
    private String login;
    private String password;
    private String email;
    @Autowired
    private RegisterDAO registerDAO = null;

...

public boolean addUser()
    {
        MyUser user = new MyUser();
        user.setLogin(login);
        user.setPassword(password);
        user.setEmail(email);
        return registerDAO.insertUserIntoDB(user) == 0 ? true : false;
    }

...
}

RegisterDAO:

public class RegisterDAO implements RegisterDAOInterface, Serializable {
    private EntityManager em;

    @PersistenceContext
    public void setEm(EntityManager em)
    {
        this.em = em;
    }


...
public int insertUserIntoDB(MyUser user)
    {
        int result = -4;
        try {
            em.persist(user);
            result = 0;

        }
        catch(Exception ex)
        {
            ex.printStackTrace();
            result = -4;
        }
        finally {

            return result;
        }
    }
...
}

I have also tried with @Transactional annotation. I configured spring applicationContext.xml like this:

<?xml version="1.0" encoding="windows-1250"?>
<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:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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
       http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
       http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd">



    <jee:jndi-lookup id="entityManagerFactory" jndi-name="myPersistenceUnit"/> 
    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
    <bean id="registerDaoImpl" class="umk.dumont.db.dao.RegisterDAO" />
    <bean id="registerModel" class="umk.dumont.models.RegisterFormModel">
        <property name="registerDAO" ref="registerDaoImpl" />
    </bean>


  <tx:annotation-driven />
  <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" />


</beans>

and annotated my addUser() method with @Transactional annotation like this:

package umk.dumont.models;

...

public class RegisterFormModel implements Serializable {
    private String login;
    private String password;
    private String email;
    @Autowired
    private RegisterDAO registerDAO = null;

...
@Transactional
public boolean addUser()
    {
        MyUser user = new MyUser();
        user.setLogin(login);
        user.setPassword(password);
        user.setEmail(email);
        return registerDAO.insertUserIntoDB(user) == 0 ? true : false;
    }

...
}

or even annotated whole class by this annotation:

package umk.dumont.models;

...
@Transactional    
public class RegisterFormModel implements Serializable {
    private String login;
    private String password;
    private String email;
    @Autowired
    private RegisterDAO registerDAO = null;

...
public boolean addUser()
    {
        MyUser user = new MyUser();
        user.setLogin(login);
        user.setPassword(password);
        user.setEmail(email);
        return registerDAO.insertUserIntoDB(user) == 0 ? true : false;
    }

...
}

but in both cases problem is the same - data doesn't stored in database. Is there any problem with my AOP proxing, because I'm newbie in this (just like in whole Spring :))?

EDIT: In my persistence.xml I am using transaction-type="JTA" so I think I should use <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" /> in my applicationContext.xml - am I right?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Arek Woźniak
  • 695
  • 3
  • 12
  • 25

3 Answers3

2

solved my problem using

org.springframework.orm.jpa.JpaTransactionManager

so your bean should be

 <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" />

hope this work!

Wilson Campusano
  • 616
  • 9
  • 21
1

In the version of the code that uses the JPA entity manager. Try adding an em.flush() after the em.persist() - all em.persist() does is to attach the entity to the persistence context. The entity is not 'persisted' at that point.

You should not need the em.flush() - but give it a try to see if it helps.

When the transaction ends then the persistence context should automatically be flushed (written to the db).

I have to say you've got quite a complicated setup here - you might need some trial & error to narrow it down. Adding JTA into the mix might not help matters - you could try with 'resource local' in Spring until you get it working. Are there any errors in the logs ?

David Victor
  • 830
  • 9
  • 29
  • I realize that for persist data to my database in transactional context, JPA needs commit or flush. But the point is, that I can't explicit use em.flush() or em.getTransaction().commit()/rollback()/begin() because JTA - which I am using - should take care of that. When I try to invoke one from above methods, then exception is thrown (something about that I can't do this in this persistence context). I think, I can manipulate transactions only by Spring Transaction Management. Logs looks fine - no errors (posted below) – Arek Woźniak Mar 10 '11 at 23:29
  • INFO: Using JTA UserTransaction: com.sun.enterprise.transaction.UserTransactionImpl@13536a8 INFO: Using JTA TransactionManager: com.sun.enterprise.transaction.TransactionManagerHelper@102ff4 INFO: Using JTA TransactionSynchronizationRegistry: com.sun.enterprise.transaction.TransactionSynchronizationRegistryImpl@1744bd3 Thanks for your reply. – Arek Woźniak Mar 10 '11 at 23:29
  • @Arek Woźniak I understand that the final solution should not directly include em.flush. But you seem to be trying lots of different options, so the suggestion is to refine down a simpler test case that works. E.g. a Junit test - maybe using in memory db - that just stores a record. Junit tests marked @Transactional will be rolled back by Spring. Once you have simple config working - add in the additional components ? Also turn on some debug logging maybe ? – David Victor Mar 11 '11 at 07:15
0

Maybe this will help:

In the JNDI case, specify the corresponding JNDI names in this post-processor's "persistenceUnits" map, typically with matching persistence-unit-ref entries in the Java EE deployment descriptor. By default, those names are considered as resource references (according to the Java EE resource-ref convention), located underneath the "java:comp/env/" namespace. For example:

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
    <property name="persistenceUnits">
        <map>
            <entry key="unit1" value="persistence/unit1"/>
            <entry key="unit2" value="persistence/unit2"/>
        </map>
    </property>
</bean>

From:

http://static.springsource.org/spring/docs/3.0.x/api/org/springframework/orm/jpa/support/PersistenceAnnotationBeanPostProcessor.html

Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • Thanks for your reply. I think the problem is not there, because JNDI works fine in my project - the name of persistence unit is resolve properly and EntityManager is injected properly. However thanks for help. – Arek Woźniak Mar 10 '11 at 23:21
  • By the way - I've checked this additional configuration - the same problem :( – Arek Woźniak Mar 10 '11 at 23:33