Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/google-chrome/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java JPA合并与持久化_Java_Jpa_Merge_Entitymanager_Persist - Fatal编程技术网

Java JPA合并与持久化

Java JPA合并与持久化,java,jpa,merge,entitymanager,persist,Java,Jpa,Merge,Entitymanager,Persist,到目前为止,我的首选是始终使用EntityManager的merge()处理插入和更新。但我也注意到merge在更新/插入之前执行额外的select查询,以确保数据库中不存在记录 现在,我正在处理一个需要大量(批量)插入数据库的项目。从性能的角度来看,在我绝对知道我总是在创建要持久化的对象的新实例的情况下,使用持久化而不是合并是否有意义?当持久化足够时,使用合并不是一个好主意-合并做了很多工作。本主题之前已经讨论过,并详细解释了它们之间的区别,使用了一些很好的流程图来说明问题。我肯定会使用per

到目前为止,我的首选是始终使用EntityManager的
merge()
处理插入和更新。但我也注意到merge在更新/插入之前执行额外的select查询,以确保数据库中不存在记录


现在,我正在处理一个需要大量(批量)插入数据库的项目。从性能的角度来看,在我绝对知道我总是在创建要持久化的对象的新实例的情况下,使用持久化而不是合并是否有意义?

持久化
足够时,使用
合并
不是一个好主意-
合并
做了很多工作。本主题之前已经讨论过,并详细解释了它们之间的区别,使用了一些很好的流程图来说明问题。

我肯定会使用persist
persist()
如果,正如您所说:

(…)我绝对知道我总是在创建一个要持久化的对象的新实例(…)


这就是此方法的全部内容—在实体已存在的情况下,它将保护您(并将回滚您的事务)。

如果您使用的是指定的生成器,则会影响性能

此外,这也是一个错误,因为受管实体由Hibernate自动管理,并且它们的状态由ON与数据库记录同步

要了解所有这些是如何工作的,您首先应该知道Hibernate将开发人员的思维方式从SQL语句转变为SQL语句

一旦一个实体由Hibernate主动管理,所有更改都将自动传播到数据库

Hibernate监视当前连接的实体。但对于要管理的实体,它必须处于正确的实体状态

首先,我们必须定义所有实体状态:

  • 新的(暂时的)

    如果新创建的对象从未与Hibernate
    会话关联过(也称为“持久性上下文”),且未映射到任何数据库表行,则该对象将被视为处于新的(暂时)状态

    要实现持久化,我们需要显式调用
    EntityManager#persist
    方法或使用可传递持久化机制

  • 持久(管理)

    持久性实体已与数据库表行关联,并由当前运行的持久性上下文管理。对此类实体所做的任何更改都将被检测并传播到数据库(在会话刷新期间)。 使用Hibernate,我们不再需要执行INSERT/UPDATE/DELETE语句。Hibernate采用一种工作方式,在当前
    会话期间的最后一个负责时刻同步更改

  • 独立的

    关闭当前运行的持久性上下文后,所有以前管理的实体都将分离。将不再跟踪连续的更改,也不会发生自动数据库同步

    要将分离的实体与活动的Hibernate会话关联,可以选择以下选项之一:

    • 重新连接

      Hibernate(但不是JPA2.1)支持通过会话更新方法重新连接。 Hibernate会话只能为给定的数据库行关联一个实体对象。这是因为持久性上下文充当内存缓存(一级缓存),并且只有一个值(实体)与给定的键(实体类型和数据库标识符)关联。 只有当没有其他JVM对象(与同一数据库行匹配)已关联到当前Hibernate会话时,才能重新附加实体

    • 合并

    合并将把分离的实体状态(源)复制到托管实体实例(目标)。如果合并实体在当前会话中没有等效实体,则将从数据库中提取一个。 即使在合并操作之后,分离的对象实例仍将保持分离状态

  • 除去

    尽管JPA要求只允许删除托管实体,但Hibernate也可以删除分离的实体(但只能通过会话#delete方法调用)。 删除的实体仅计划删除,实际的数据库DELETE语句将在会话刷新期间执行

为了更好地理解JPA状态转换,您可以可视化下图:

或者,如果您使用特定于Hibernate的API:


这样做是否是一种好的编码实践:try{em.persist(xxx);}catch(RuntimeException re){try{xxx=em.merge(xxx);}catch(Exception e){throw e;}}尽管捕获
RuntimeException
肯定不是一种好的实践(但我假设你的意思是
EntityExistsException
)我不认为这是一种通用的良好编码实践。这取决于你的要求。如果需求要求必须持久化该对象,并且在该操作发生之前该对象不能存在,我肯定不会在捕获异常后尝试进行合并。此外,如果您使用JTA实体管理器,您的事务此时将被标记为回滚。您能否解释一下“此外,如果您使用JTA实体管理器,您的事务此时将被标记为回滚”是什么意思?我正在为EJB3使用CMT,并且我能够验证,只要我在方法边界内执行异常,就不会回滚任何事务。@phewataal我猜当您对已经存在的实体调用
persist
时,您将获得
EntityExistsException
,由于JPA实现者的原因,该事务将回滚(不是因为它是运行时异常)。换句话说,我认为(不确定)即使您尝试/捕获此异常,tx仍将标记为回滚。
merge
将永远不会抛出
EntityExistsException