Hibernate 在从相关实体中删除时加载 LOBS(不应该是懒惰的)吗?

Posted

技术标签:

【中文标题】Hibernate 在从相关实体中删除时加载 LOBS(不应该是懒惰的)吗?【英文标题】:Hibernate loads LOBS on deleting from related entity (Shouldn't it be Lazy)? 【发布时间】:2019-02-21 18:03:40 【问题描述】:

我有一个使用 JPA 和 Hibernate 进行数据库交互的 Web 应用程序。

现在有一个通用 JPA 存储库一个实体,我遇到了问题。 现在在调用删除方法时,我得到一个 java.lang.OutOfMemoryError: Java heap space Exception。 (它是 deleteByCreatedDateLessThan)。

当表中只有一些条目时(用 20 个测试),这可以正常工作,但对于高达 20.000 的实际负载。

分析 Dump 后发现,应用程序正在从数据库加载整个 IbGeneratedData.IbPdf 和 IbGeneratedData.IbXml(填满了 80% 的堆空间)。 我怎样才能阻止这个?要删除它应该只检查 ID 以删除它们...

我在 LOB 上也试过 @Basic(fetch=FetchType.LAZY)

public interface ResponseRepository extends JpaRepository<IbResponse, String>, JpaSpecificationExecutor<IbResponse> 
    @Modifying
    void deleteByCreatedDateLessThan(Date maxAgedDate);

    Collection<IbResponse> findByOwningUserIdEquals(String id, Sort sort);




@Entity(name = "IbResponse")
@Table(name = "IB_RESPONSE")
public class IbResponse implements Serializable 

    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    @Column(name = "ID")
    private String id;

    @ManyToOne(fetch = FetchType.LAZY, optional = false, targetEntity = IbUser.class)
    @JoinColumn(name = "USER_ID", updatable = false)
    private IbUser owningUser;

    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "GENERATED_DATA_ID")
    private IbGeneratedData generatedData;

    ...


@Entity(name = "IbGeneratedData")
@Table(name = "IB_GENERATED_DATA")
public class IbGeneratedData implements Serializable 

    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    @Column(name = "ID")
    private String id;

    @Lob
    @Column(name = "PDF")
    private byte[] IbPdf;

    @Lob
    @Column(name = "XML")
    private byte[] IbXml;

    ...

Spring-data-jpa:1.7.0 休眠:4.3.7 在 Oracle 数据库上运行

【问题讨论】:

可能是related question。 【参考方案1】:

1) LAZY 只是对持久化提供者的提示,不是必须的。

2) deleteBy 在 Spring Data Jpa 中的工作方式,根据 JPA 标准是正确的,它首先将所有实体加载到持久化上下文中,然后调用 delete(entity)每个结果。

解决方案

创建更新查询并在新事务中运行它(propagation.REQUIRES_NEW):

@Modifying
@Query("delete from IbResponse i where i.createdDate < :date", )
void deleteByCreatedDateLessThan(@Param("date") Date date);

这将省略将实体加载到持久性上下文中并执行直接批量删除。

【讨论】:

您好,谢谢您-我的朋友现在确实提供了几乎相同的解决方案(没有原因)-除了使用 @Query 我们更改了关系:让 IB_GENERATED_DATA 存储 id响应。但是:我仍然不明白为什么在这种情况下它没有将所有实体加载到上下文中。

以上是关于Hibernate 在从相关实体中删除时加载 LOBS(不应该是懒惰的)吗?的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate - 删除子项时如何从父项中删除实体

为啥在本机查询 Hibernate 延迟加载的子实体中?

hibernate 延迟加载

Spring / Hibernate - 删除实体时抛出 StaleStateException

JavaWeb系列——Hibernate——延迟加载(转)

删除父级和所有子级