处理JPA合并的最佳方法是什么?

Man*_*anu 10 jpa jta

我是整个JPA的新手,所以我有很多关于处理JPA合并和持久化的最佳方法的问题.

  1. 我有一个应该更新的用户对象(一些值,如日期和名称).我必须首先合并传递的对象还是更安全地找到新对象?

    目前我更新用户的代码如下所示:

    public void updateUserName(User user, String name) {
         // maybe first merge it?
         user.setName(name);
         user.setChangeDate(new Date());
         em.merge(user);   
     }
    
    Run Code Online (Sandbox Code Playgroud)

    在调用更新方法之前,如何确保用户未被操作?做这样的事更安全:

     public void updateUserName(int userId, String name) {
         User user = em.getReference(User.class, userId);
         user.setName(name);
         user.setChangeDate(new Date());
         em.merge(user);   
     }
    
    Run Code Online (Sandbox Code Playgroud)

    也许其他解决方案 我观看了多个视频并看到了许多例子,但它们都不同,没有人解释最佳做法是什么.

  2. 将孩子添加到关系中的最佳方法是什么?例如,我的用户对象与多个组有连接.我应该为用户调用JPA处理程序,只是将新组添加到用户组列表中,还是应该使用persist在so组处理程序中创建组,并将其手动添加到我的用户对象中?

希望有人在这里有一个线索;)

Pio*_*cki 7

  1. 这取决于您想要实现的内容以及您尝试合并的对象的来源有多少信息.

    首先,如果您em.merge(user)在方法的第一行调用或最终调用无关紧要.如果使用JTA和CMT,则在方法调用完成时将更新您的实体.唯一的区别是,如果em.merge(user)在更改用户之前调用,则应使用返回的实例而不是参数,因此它是:

    public void updateUserName(User user, String name) {
       User managedUser = em.merge(user);
       managedUser.setChangeDate(new Date());
       // no need of additional em.merge(-) here.
       // JTA automatically commits the transaction for this business method.
    }
    
    Run Code Online (Sandbox Code Playgroud)

    要么

    public void updateUserName(User user, String name) {
       user.setChangeDate(new Date());
       em.merge(user);
       // JTA automatically commits the transaction for this business method.
    }
    
    Run Code Online (Sandbox Code Playgroud)

    现在关于更新实体.
    如果您只想更新实体中一些明确定义的字段 - 请使用第二种方法,因为它更安全.您无法确定方法的客户端是否未修改实体的某些其他字段.因此,em.merge(-)也会更新它们,这可能不是您想要实现的目标.

    另一方面 - 如果你想接受用户所做的所有更改,只是覆盖/添加一些属性,例如changeDate你的例子,第一种方法也很好(合并整个实体传递给业务方法.)这实际上取决于你的使用-案件.

  2. 我想这取决于你的级联设置.如果你想GroupsUser实体被更改时自动持久/合并- 只需将它添加到用户的集合中就可以了(例如User#addGroup(Group g) { groups.add(g)}.如果你不想级联,你可以随时创建自己的方法,传播到另一个关系的一面.它可能是这样的:User#addGroup(Group g)自动调用g.addUser(this);.


ben*_*n75 4

问题1

  • 必须在分离的merge实体上调用该方法。
  • 该方法将返回附加到entityManager 的merge合并对象。

这是什么意思 ?

一旦用于获取实体的实体管理器关闭,实体就会被分离。(即大多数时候是因为您在之前的事务中获取了它)。

在您的第二个代码示例中:用户已附加(因为您只是获取它),因此调用合并是没有用的。(顺便说一句:不是getReference但是find

在您的第一个示例中:我们不知道用户的状态(是否分离实体?)。如果它是分离的,则调用 是有意义的merge,但要小心merge不要修改作为参数传递的对象。这是我的第一个示例的版本:

/**
 * @param user : a detached entity
 * @return : the attached updated entity
**/
public User updateUserName(User user, String name) {
   user.setName(name);
   user.setChangeDate(new Date());
   return em.merge(user);   
}
Run Code Online (Sandbox Code Playgroud)

问题2

也许一些代码示例来解释 jpa 处理程序的含义可以帮助我们理解您的担忧。无论如何,我会尽力帮助你。

如果您有持久用户并且需要创建一个新组并将其与持久用户关联:

User user = em.find(User.class, userId);
Group group = new Group();
...
em.persist(group);
user.addToGroups(group);
group.addToUsers(user); //JPA won't update the other side of the relationship
                        //so you have to do it by hand OR being aware of that 
Run Code Online (Sandbox Code Playgroud)

如果您有一个持久用户和一个持久组,并且需要将它们关联起来:

User user = em.find(User.class, userId);
Group group = em.find(Group.class, groupId);
...
user.addToGroups(group);
group.addToUsers(user);
Run Code Online (Sandbox Code Playgroud)

一般考虑因素

关于所有这些的最佳实践实际上取决于您管理事务(以及实体管理器的生命周期)与对象的生命周期。

大多数时候:entityManager 是一个生命周期非常短的对象。另一方面,您的业务对象可能会存在更长时间,因此您必须调用合并(并注意合并不会修改参数中传递的对象!!!)。

您可以决定在同一个事务中获取和修改您的业务对象(即使用相同的entityManager):这意味着更多的数据库访问,并且出于性能原因,此策略通常必须与二级缓存相结合。但在这种情况下,您不必调用 merge。

我希望这有帮助。