Hello, folks! I need optimization suggestions for lazily initialized collections. I will first describe the code, then the problem. Any help is greatly appreciated!
***
Situation details
@Entity public class User { @Id @Column(name = "USER_ID", nullable = false, precision = 20) private Long id;
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.ALL) @BatchSize(size = 10) private Set<Vote> votes; }
@Entity public class Product { @Id @Column(name = "PRODUCT_ID", nullable = false, precision = 20) private Long id;
@OneToMany(mappedBy = "product", fetch = FetchType.LAZY, cascade = CascadeType.ALL) @BatchSize(size = 10) private Set<Vote> votes; }
@Entity public class Vote { @Id @Column(name = "VOTE_ID", nullable = false, precision = 20) private Long id;
@Column(name = "CASTED_VOTE", precision = 3, scale = 2, columnDefinition = "NUMBER(3,2)") private Double castedVote;
@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "USER_ID_REF") private User user;
@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "PRODUCT_ID_REF") private Product product; }
Essentially, Vote is an association table between User and Product in a many-to-many bidirectional relationship (@ManyToMany annotation cannot be used though because there are other columns in the Vote table, namely, CASTED_VOTE).
For example, we have two Users, "Ivanoff" and "Petroff", and two Products, "Balalaika" and "Vodka". Each user casts votes for every product, so we have four votes total, { vote1, vote2, vote3, vote4 }:
Ivanoff.votes = { vote1, vote2 } Petroff.votes = { vote3, vote4 }
Balalaika.votes = { vote1, vote3 } Vodka.votes = { vote2, vote4 }
***
Problem details
When I access User#votes, it is lazily initialized. The Select to the database looks as such (simplified for easier understanding):
select vote0_.VOTE_ID, ... blah-blah-blah... from VOTE vote0_ where vote0_.USER_ID_REF in (?, ?)
Similarly, when I access Product#votes, the Select to the database looks as such:
select vote0_.VOTE_ID, ... blah-blah-blah... from VOTE vote0_ where vote0_.PRODUCT_ID_REF in (?, ?)
So, two different selects are performed to initialize the same objects. When I have initialized one of the lazy associations I want to be able to load at least some of the elements of the second lazy association from the cache, not from the database. When I use the batch fetching mode for the votes and iterate through all the users, every possible vote row there is is initialized. Then, when I iterate through all the products, the votes are initialized from the database again, not from the cache. Collection of users is relatively small, collection of products is vast. It is crucial for me that only one select to the database is performed. How can I solve this problem?
|