1

I am developing an application with Struts2, Spring and Hibernate and I'm working on models fetch optimization. For this example, consider that the "example_table" may have more than 500k records, and all his OneToMany relation may have many more records (ex. document table in relation with document_row).

Here is the example code:

@Entity
@Table(name = "example")
public class Example extends BaseModel { // Base Model is mapped as superclass and contains the Id column and create,update,delete timestamps
    private String exampleName;

    /*
     * ...
     */

    /* 
     * This relation contains another relation inside it  
     * (ex. Set<ExampleRelationRelation> exampleRelationRelations)
     */
    private ExampleRelation1 exampleRelation1;

    private Set<ExampleRelation2> exampleRelations2;

    // COSTRUCTORS --------------------------------------------------------
    /*
     * Entity constructors
     */

    // GETTER AND SETTER --------------------------------------------------
    @Column(name = "exampleName")
    public String getExampleName() {
        return exampleName;
    }

    public void setExampleName(String exampleName) {
        this.exampleName = exampleName;
    }

    /*
     * ...
     */

    @OneToOne(mappedBy = "example_relation_1", cascade = CascadeType.ALL, fetch = FetchType.LAZY, targetEntity = ExampleRelation1.class)
    @NotFound(action = NotFoundAction.IGNORE)
    public ExampleRelation1 getExampleRelation1() {
        return exampleRelation;
    }

    public void setExampleRelation1(ExampleRelation1 exampleRelation1) {
        this.exampleRelation1 = exampleRelation1;
    }

    @OneToMany(mappedBy = "example", targetEntity = ExampleRelation2.class, fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @NotFound(action = NotFoundAction.IGNORE)
    public Set<ExampleRelation2> getExampleRelation2() {
        return exampleRelation2;
    }

    public void setExampleRelation2(Set<ExampleRelation2> exampleRelation2) {
        this.exampleRelation2 = exampleRelation2;
    }
}

In my application I might need to load Example with ExampleRelation1 and his child relation exampleRelationRelations, but not always. Maybe next time I have to load Example with no relations or just with exampleRelation1 and exampleRelation2.

The best solution I've found is to implement the Fetch profiles in order to dynamically join the table with the relations I need. With this solution I can tell to Struts2 controller to retrieve the data I need.

Is this a good solution? or should i use other strategies?

* EDIT *

I've found also this question, it may be a solution?

Community
  • 1
  • 1
IlGala
  • 3,331
  • 4
  • 35
  • 49
  • 1
    Both topics have opposite behavior of lazy loading feature. BTW why are you loading more than 500k records, it's hard to process them. – Roman C Sep 13 '15 at 17:50
  • I probably I have explained myself in a bad way... 500k is the table size, of course for a web application will be madness showing in a single view 500k records with relations without paginate them... – IlGala Sep 13 '15 at 17:54
  • Also if the related object has 1:n or n:n relations? – IlGala Sep 13 '15 at 19:20
  • Thanks for your suggestion! – IlGala Sep 14 '15 at 05:56

1 Answers1

0

Fetch Profiles can be an answer for your problem.

But you can control this behaviour on code, just lazy loading the entities you want calling the right method each time inside a transaction.

I might need to load Example with ExampleRelation1 and his child relation exampleRelationRelations

So, you can use something like that:

@Transactional // from Spring
public Example getExampleWithExampleRelation1AndExampleRelationRelations(String exampleName) {

    Example example = em.find(Example.class, exampleName);
    ExampleRelation1 exampleRelation1 = example.getExampleRelation1(); //lazy load
    exampleRelation1.exampleRelationRelations().size(); //lazy load list
    return example;
}

Maybe next time I have to load Example with no relations or just with exampleRelation1 and exampleRelation2.

Just create another method and call it:

@Transactional // from Spring
public Example getExampleWithExampleRelation1AndExampleRelation2(String exampleName) {

    Example example = em.find(Example.class, exampleName);
    example.getExampleRelation1(); //lazy load
    example.getExampleRelation2(); //lazy load
    return example;
}

You can also use JPQL and join with the FETCH word to bring the entities using only one query, like:

String jpql = "SELECT e FROM Example e " + 
    "JOIN FETCH e.ExampleRelation1" + 
    "JOIN FETCH e.ExampleRelation2 ";
Dherik
  • 17,757
  • 11
  • 115
  • 164