使用JPA进行更新的最佳方法

时间:2010-10-06 08:51:09

标签: java jpa

使用JPA我应该在更新时遵循哪种方法?

接近1

obj o = new obj()
o.setName('val')
set other values
entitymanger.merge(ibj)

接近2

obj o = getObjFromDb(obj)
obj.setval(name)
//not am not updating other attributes

entitymanage.merge(obj)

2 个答案:

答案 0 :(得分:4)

你真的需要理解merge操作的语义,所以我将重复JPA规范所说的内容:

  

3.2.4.1合并分离的实体状态

     

合并操作允许   从分离的国家传播   实体到持久化实体   由EntityManager管理。

     

合并操作的语义   应用于实体X如下:

     
      
  • 如果X是分离的实体,则X的状态将复制到预先存在的实体上   管理实体实例X'相同   X的身份或新的托管副本X'   已创建。
  •   
  • 如果X是新的实体实例,则创建新的管理实体实例X'   并将X的状态复制到   新的托管实体实例X'。
  •   
  • 如果X是已移除的实体实例,则IllegalArgumentException将是。{   由合并操作抛出(或者   事务提交将失败)。
  •   
  • 如果X是托管实体,则合并操作会忽略它,   但是,合并操作是   级联到由...引用的实体   X的关系,如果这些   关系已被注释   级联元素值   cascade=MERGEcascade=ALL   注释
  •   
  • 对于来自X的关系引用的所有实体Y具有   级联元素值cascade=MERGE或   cascade=ALL,Y以递归方式合并   作为Y'。对于所有这样的Y引用   X,X'设置为引用Y'。 (注意   如果X被管理,那么X就是   与X'相同的对象。)
  •   
  • 如果X是合并到X'的实体,则引用另一个实体Y,其中   cascade=MERGEcascade=ALL是。{   未指定,然后导航   来自X'的相同关联产生a   引用托管对象Y'   与Y相同的持久性身份。
  •   
     

持久性提供程序不能   合并标记为LAZY的字段没有   被抓取:它必须忽略这样   合并时的字段。

     

使用的任何Version列   必须通过实体检查实体   持久性运行时实现   在合并操作期间和/或在   刷新或提交时间。离席期间   Version列中没有   其他版本检查由   持久性提供程序运行时   合并期间。

换句话说,merge操作将传递的实体的状态复制到具有相同数据库标识的托管实体(如果需要,将在持久性上下文中加载)和然后返回对该托管实体的引用(并且传递的对象未附加到持久化上下文)。

现在回到最初的问题。在这两种情况下,将使用传递的实体的完整状态覆盖数据库值,包括非null(和null)值。在实践中:

  • 方法2,即直接在分离的实体上工作更容易
  • 方法1听起来像DTO反模式,意味着更多的痛苦

如果可以,请选择接近2。

相关问题

答案 1 :(得分:2)

您首先创建新对象,因此合并不会更新对象,而是将新的对象放入数据库。所以方法2看起来更好。但是看看你对getObjFromDb关于交易的评论,我必须注意方法:合并持久删除应该在事务范围内完成。

更好的解决方案伪代码是:

boolean transactionClosed = false;
entitymanage.getTransaction().begin();
try{
   obj o = entitymanage.find( someKey );
   o.setval(name);
   entitymanage.getTransaction().commit();
   transactionClosed = true;
}
finally{
   if( !transactionClosed )
       entitymanage.getTransaction().rollback();
}