JPA EntityManager: Why use persist() over merge()?

后端 未结 15 1615
说谎
说谎 2020-11-22 03:09

EntityManager.merge() can insert new objects and update existing ones.

Why would one want to use persist() (which can only create new objec

15条回答
  •  不要未来只要你来
    2020-11-22 03:40

    Persist and merge are for two different purposes (they aren't alternatives at all).

    (edited to expand differences information)

    persist:

    • Insert a new register to the database
    • Attach the object to the entity manager.

    merge:

    • Find an attached object with the same id and update it.
    • If exists update and return the already attached object.
    • If doesn't exist insert the new register to the database.

    persist() efficiency:

    • It could be more efficient for inserting a new register to a database than merge().
    • It doesn't duplicates the original object.

    persist() semantics:

    • It makes sure that you are inserting and not updating by mistake.

    Example:

    {
        AnyEntity newEntity;
        AnyEntity nonAttachedEntity;
        AnyEntity attachedEntity;
    
        // Create a new entity and persist it        
        newEntity = new AnyEntity();
        em.persist(newEntity);
    
        // Save 1 to the database at next flush
        newEntity.setValue(1);
    
        // Create a new entity with the same Id than the persisted one.
        AnyEntity nonAttachedEntity = new AnyEntity();
        nonAttachedEntity.setId(newEntity.getId());
    
        // Save 2 to the database at next flush instead of 1!!!
        nonAttachedEntity.setValue(2);
        attachedEntity = em.merge(nonAttachedEntity);
    
        // This condition returns true
        // merge has found the already attached object (newEntity) and returns it.
        if(attachedEntity==newEntity) {
                System.out.print("They are the same object!");
        }
    
        // Set 3 to value
        attachedEntity.setValue(3);
        // Really, now both are the same object. Prints 3
        System.out.println(newEntity.getValue());
    
        // Modify the un attached object has no effect to the entity manager
        // nor to the other objects
        nonAttachedEntity.setValue(42);
    }
    

    This way only exists 1 attached object for any register in the entity manager.

    merge() for an entity with an id is something like:

    AnyEntity myMerge(AnyEntity entityToSave) {
        AnyEntity attached = em.find(AnyEntity.class, entityToSave.getId());
        if(attached==null) {
                attached = new AnyEntity();
                em.persist(attached);
        }
        BeanUtils.copyProperties(attached, entityToSave);
    
        return attached;
    }
    

    Although if connected to MySQL merge() could be as efficient as persist() using a call to INSERT with ON DUPLICATE KEY UPDATE option, JPA is a very high level programming and you can't assume this is going to be the case everywhere.

提交回复
热议问题