EntityManager.merge not doing anything

31,507

Solution 1

Try the em.flush() also after the em.merge(). Sometimes the EntityManager just keeps the the changes for updating later.

Solution 2

EntityManager autocommit is false. Please use transaction like below;

EntityManager em = null;
EntityTransaction t = null;
try {
    em = emf.createEntityManager();
    t = em.getTransaction();
    t.begin();
    em.merge(myTestObject);
    t.commit();
} catch (Exception e) {
    t.rollback();
    throw new RuntimeException(e.getMessage());
}finally{
    if(em != null)
        em.close();
}

Solution 3

I had the very issue and got resolved by changing the scope.

@PersistenceContext(type=PersistenceContextType.EXTENDED)

ref: Manipulating Entities with EntityManager

Solution 4

Where is the transaction.begin() and transaction.end() methods? In RESOURCE_LOCAL you should manage the transaction and not the application...

Share:
31,507
digitaljoel
Author by

digitaljoel

Professional Java programmer since 2000 working with Spring, JPA, hibernate, maven, and other related technologies. Also an AKKI Kenpo black belt.

Updated on August 05, 2022

Comments

  • digitaljoel
    digitaljoel almost 2 years

    I have a User entity:

    @Entity
    @Table( name = "bi_user" )
    @SequenceGenerator( name = "USER_SEQ_GEN", sequenceName = "USER_SEQUENCE" )
    public class User
            extends DataObjectAbstract<Long>
    {
        private static final long serialVersionUID = -7870157016168718980L;
    
        /**
         * key for this instance. Should be managed by JPA provider.
         */
        @Id
        @GeneratedValue( strategy = GenerationType.SEQUENCE, generator = "USER_SEQ_GEN" )
        private Long key;
    
        /**
         * Username the user will use to login.  This should be an email address
         */
        @Column( nullable=false, unique=true)
        private String username;
    
        // etc. other columns and getters/setters
    }
    

    Where DataObjectAbstract is a simple @MappedSuperClass that has a jpa version and equals/hashcode definition.

    I have a base dao class that looks like this

    public abstract class BaseDaoAbstract<T extends DataObject<K>, K extends Serializable>
            implements BaseDao<T, K>
    {
    
        @PersistenceContext
        private EntityManager em;
    
        /**
         * Save a new entity. If the entity has already been persisted, then merge
         * should be called instead.
         * 
         * @param entity The transient entity to be saved.
         * @return The persisted transient entity.
         */
        @Transactional
        public T persist( T entity )
        {
            em.persist( entity );
            return entity;
        }
    
        /**
         * merge the changes in this detached object into the current persistent
         * context and write through to the database. This should be called to save
         * entities that already exist in the database.
         * 
         * @param entity The entity to be merged
         * @return The merged entity.
         */
        @Transactional
        public T merge( T entity )
        {
            return em.merge( entity );
        }
    
        // other methods like persist, delete, refresh, findByKey that all delegate to em.
    }
    

    I have defined the OpenEntityManagerInView filter in web.xml as follows

    <filter>
        <filter-name>openEntityManagerInViewFilter</filter-name>
        <filter-class>
            org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
        </filter-class>
        <init-param>
            <param-name>entityManagerFactoryBeanName</param-name>
            <param-value>biEmf</param-value>
        </init-param>
    </filter>
    
    <filter-mapping>
        <filter-name>openEntityManagerInViewFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    

    I recently upgrade to eclipselink 2.3.2 and Spring 3.1 and converted from CGLIB proxies to Load Time Weaving with aspectJ for Spring but I did not configure LTW for eclipselink.

    The problem is in this code which lives in a spring ApplicationListener, see comments.

            User user = userService.findByKey(userDetails.getKey());
    
            // THIS MERGE NEVER WRITES THROUGH TO THE DATABASE.
            // THIS DOESN'T WORK AS PERSIST EITHER
            user = userService.merge( user.loginSuccess() );
    

    user.loginSuccess just sets some fields and returns this I'm certain it's getting through the code because I get log statements around it and I can set a breakpoint and walk through it. My postgres log doesn't show any traffic getting to postgres for the merge.

    I am saving other stuff all over the place without issue, including users in another location when they change their password, and I know this code used to work. Is there something obviously amiss here? Am I using the OpenEntityManagerInViewFilter incorrectly? Should I need to be in a @Transactional method in order for the entities to be considered managed? Any help is appreciated.

    Update I tried the flush as suggested by prajeesh. Here's the code

    @Transactional
    public T merge( T entity )
    {
        entity = em.merge( entity );
        em.flush();
        return entity;
    }
    

    in a class in com.bi.data. I have this in my spring app config file

    <context:component-scan base-package="com.bi.controller,com.bi.data,com.bi.web" />
    

    In my spring configuration I have

    <context:load-time-weaver/>
    <tx:annotation-driven mode="aspectj"/>    
    

    with an aop.xml that looks like this:

    <aspectj>
        <weaver>
            <!-- only weave classes in our application-specific packages -->
            <include within="com.bi..*"/>
        </weaver>
    </aspectj>
    

    and I got a

    javax.persistence.TransactionRequiredException: 
    Exception Description: No transaction is currently active
    

    So something is obviously misconfigured, but what?

    Update 2: I reverted my changes to enable load time weaving and now the merge goes through with or without the flush, but I still don't understand what the problem is with LTW...

  • vicky
    vicky over 8 years
    i am using jpa and it doesn't allow em.getTransaction(),
  • ethemsulan
    ethemsulan over 8 years
    Sometimes JPA can not find persistence.xml file in path. Where your persistence.xml path? If your em is null, move persistence.xml to src/main/java/META-INF/persistence.xml
  • Zouhair Kasmi
    Zouhair Kasmi about 5 years
    I search for this solution several months, in a big project thank you!