3

I have a web application using JPA and Hibernate for the DB interactions.

There is one generiec JPA repository one entity I got problems with now. Now on calling a delete method I get a java.lang.OutOfMemoryError: Java heap space Exception. (it is the deleteByCreatedDateLessThan).

When there are only some entries in the tables (tested with 20) this works fine, but for real load up to 20.000.

After analyzing the Dump it turned out that the application is loading the whole IbGeneratedData.IbPdf & IbGeneratedData.IbXml from the data base (filled up 80% of the heapspace).
How can I stop this? For deleting it should just check the IDs to delete them ...

I tried as well @Basic(fetch=FetchType.LAZY) on the LOB.

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
Hibernate: 4.3.7
Running on Oracle Database

PaulEdison
  • 897
  • 1
  • 15
  • 36

1 Answers1

3

1) LAZY is only a hint for the persistence provider, its not a must.

2) The way deleteBy works in Spring Data Jpa, which is correct according to JPA standards, is that it loads all the entities first into the persistence context and then invoked delete(entity) for each of the results.

Solution

Create an update query and run it in a new transaction (propagation.REQUIRES_NEW) :

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

This will omit the loading of entities into the persistence context and perform a straight batch delete.

Maciej Kowalski
  • 25,605
  • 12
  • 54
  • 63
  • Hi thanks for that - friend of mine did now provide almost the same solution (without the cause) - additionally to the use of the @Query we changed the relation: to have the IB_GENERATED_DATA store the id of the response. BUT: I still don't really understand why in this case it is NOT loading all the entities into the context. – PaulEdison Feb 24 '19 at 16:18