Announcement Announcement Module
Collapse
No announcement yet.
Open new transaction in <persistense-context> flow Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Open new transaction in <persistense-context> flow

    Hi all,

    I'm using spring + spring web flow + richfaces + jpa (hibernate)

    I have a flow with <persistense-context> defined
    I have a simple form binded with an entity and a button that fires a save method in my spring service. In the save method I need to get the old information about the entity in order to compare it to the new one.

    I have a method annotated with @Transactional(propagation = Propagation.REQUIRES_NEW) in my DAO to return the old data.

    when this method is executed I have the following log:
    10:27:47,500 DEBUG AnnotationTransactionAttributeSource:107 - Adding transactional method [findByIdNewTransaction] with attribute [PROPAGATION_NESTED,ISOLATION_DEFAULT]
    10:27:47,500 DEBUG JpaTransactionManager:285 - Found thread-bound EntityManager [org.hibernate.ejb.EntityManagerImpl@1998df4] for JPA transaction
    10:27:47,515 DEBUG JpaTransactionManager:371 - Creating new transaction with name [eu.dreamix.brokers.model.dao.BaseDao.findByIdNewTr ansaction]: PROPAGATION_NESTED,ISOLATION_DEFAULT
    10:27:47,515 DEBUG DriverManagerDataSource:163 - Creating new JDBC DriverManager Connection to [jdbc:mysql://localhost/brokers?characterEncoding=UTF-8]
    10:27:47,578 DEBUG JpaTransactionManager:348 - Exposing JPA transaction as JDBC transaction [SimpleConnectionHandle: com.mysql.jdbc.Connection@1afed5e]
    Hibernate: update users set active=?, date_created=?, date_modified=?, contract=?, password=?, username=? where id=?
    Hibernate: select user0_.id as id28_, user0_.active as active28_, user0_.date_created as date3_28_, user0_.date_modified as date4_28_, user0_.contract as contract28_, user0_.password as password28_, user0_.username as username28_ from users user0_ where user0_.id=? limit ?

    If I remove the the <persistance-context> tag the log is the following:
    10:57:38,109 DEBUG AnnotationTransactionAttributeSource:107 - Adding transactional method [findByIdNewTransaction] with attribute [PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT]
    10:57:38,109 DEBUG JpaTransactionManager:371 - Creating new transaction with name [eu.dreamix.brokers.model.dao.BaseDao.findByIdNewTr ansaction]: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT
    10:57:38,125 DEBUG JpaTransactionManager:322 - Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl@70b02c] for JPA transaction
    10:57:38,125 DEBUG DriverManagerDataSource:163 - Creating new JDBC DriverManager Connection to [jdbc:mysql://localhost/brokers?characterEncoding=UTF-8]
    10:57:38,203 DEBUG JpaTransactionManager:348 - Exposing JPA transaction as JDBC transaction [SimpleConnectionHandle: com.mysql.jdbc.Connection@15fea73]
    Hibernate: select user0_.id as id28_, user0_.active as active28_, user0_.date_created as date3_28_, user0_.date_modified as date4_28_, user0_.contract as contract28_, user0_.password as password28_, user0_.username as username28_ from users user0_ where user0_.id=? limit ?

    The difference is that there is an update statement before the select when I use the <persistance-context> tag. This update statement updates the DB with the new values in the entity and the select returns the new data, not the old one.

    If I remove the <persistance-context> tag it works, but I get lazy initialization exceptions.

    I can store the new data in another object and then after the comparison between the new data and the old I'll copy it to the entity and save it, but I don't like this solution.

    Any ideas?

  • #2
    The transaction is made for the already existing session, which has dirty data so hibernate flushes before querying, this is default behavior for hibernate. Either set flushmode to manual or commit (it now probably is auto) or make the transaction readonly (readonly=true) that should also prevent the flush.

    Comment


    • #3
      Hi, and thanks for the reply!

      I put readOnly=true and now there is no update statement. Still I cannot get the data from the DB
      This is my code:
      Code:
          public void save(User entity, UsersHelper usersHelper) {
              String password = entity.getPassword();
              if (StringUtils.hasText(password)) {
                  entity.setPassword(SecurityUtils.hashPassword(entity.getUsername(), password));
              } else {
                  User old = findByIdNewTransaction(entity.getId());
                  String oldPassword = old.getPassword();
                  entity.setPassword(oldPassword);
              }
      If I remove the <persistence-context> tag I get the old password. If I have this tag, old.getPassword(); returns the new one.

      Here is the log with <persistence-context>

      13:48:58,593 DEBUG AnnotationTransactionAttributeSource:107 - Adding transactional method [findByIdNewTransaction] with attribute [PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT,readOnl y]
      13:48:58,593 DEBUG JpaTransactionManager:285 - Found thread-bound EntityManager [org.hibernate.ejb.EntityManagerImpl@1f2a8f5] for JPA transaction
      13:48:58,593 DEBUG JpaTransactionManager:371 - Creating new transaction with name [eu.dreamix.brokers.model.dao.BaseDao.findByIdNewTr ansaction]: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT,readOnl y
      13:48:58,593 DEBUG DriverManagerDataSource:163 - Creating new JDBC DriverManager Connection to [jdbc:mysql://localhost/brokers?characterEncoding=UTF-8]
      13:48:58,609 DEBUG JpaTransactionManager:348 - Exposing JPA transaction as JDBC transaction [SimpleConnectionHandle: com.mysql.jdbc.Connection@12036a1]
      Hibernate: select user0_.id as id28_, user0_.active as active28_, user0_.date_created as date3_28_, user0_.date_modified as date4_28_, user0_.contract as contract28_, user0_.password as password28_, user0_.username as username28_ from users user0_ where user0_.id=? limit ?
      13:48:59,593 DEBUG JpaTransactionManager:730 - Initiating transaction commit
      13:48:59,593 DEBUG JpaTransactionManager:451 - Committing JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@1f2a8f5]
      13:48:59,593 DEBUG JpaTransactionManager:539 - Not closing pre-bound JPA EntityManager after transaction

      and without <persistence-context>

      13:46:57,125 DEBUG AnnotationTransactionAttributeSource:107 - Adding transactional method [findByIdNewTransaction] with attribute [PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT,readOnl y]
      13:46:57,140 DEBUG JpaTransactionManager:371 - Creating new transaction with name [eu.dreamix.brokers.model.dao.BaseDao.findByIdNewTr ansaction]: PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT,readOnl y
      13:46:57,140 DEBUG JpaTransactionManager:322 - Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl@2be20e] for JPA transaction
      13:46:57,156 DEBUG DriverManagerDataSource:163 - Creating new JDBC DriverManager Connection to [jdbc:mysql://localhost/brokers?characterEncoding=UTF-8]
      13:46:57,203 DEBUG JpaTransactionManager:348 - Exposing JPA transaction as JDBC transaction [SimpleConnectionHandle: com.mysql.jdbc.Connection@cf9a33]
      Hibernate: select user0_.id as id28_, user0_.active as active28_, user0_.date_created as date3_28_, user0_.date_modified as date4_28_, user0_.contract as contract28_, user0_.password as password28_, user0_.username as username28_ from users user0_ where user0_.id=? limit ?
      13:46:58,578 DEBUG JpaTransactionManager:730 - Initiating transaction commit
      13:46:58,578 DEBUG JpaTransactionManager:451 - Committing JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@2be20e]
      13:46:58,578 DEBUG JpaTransactionManager:534 - Closing JPA EntityManager [org.hibernate.ejb.EntityManagerImpl@2be20e] after transaction
      13:46:58,578 DEBUG EntityManagerFactoryUtils:313 - Closing JPA EntityManager

      Comment


      • #4
        I should read better .

        Only starting a new transaction isn't enough. It is going to use the same session and thus the same first and/or second level cache, resulting in the same object being returned.

        So what you actually need to do is open a new hibernate session and use that to retrieve the data from the database. It has to be a new seperate session.

        Comment


        • #5
          Thanks, now it works.

          I made my method looks like this:

          Code:
          @PersistenceUnit
          private EntityManagerFactory emf;
          
          public T findByIdNewTransaction(Long id) {
                  EntityManager webFlowManager = entityManager;
                  this.entityManager = emf.createEntityManager();
                  try {
                      return findById(id);
                  } finally {
                      this.entityManager = webFlowManager;
                  }
          }

          Comment


          • #6
            I wouldn't do it like that... You might run in concurrency/multi threading issues here, you are replacing the internal instance... I would simply make a new one inside this method and use it directly instead of replacing the internal one.

            Comment


            • #7
              My mistake! Thanks for the help.

              Comment

              Working...
              X