I'm in the process of writing a Java based server for an existing MySQL database. I can change the structure of the database, yet any change also means digging through a quite old CakePHP project and I'd like to leave that one untouched as much as possible.
I have not very much experience with database access in Java, so when I started looking for a good framework, I ended up with Spring Data Repositories (mostly because I already had Spring Boot Actuator for REST services) and because rolling Hibernate or other JPA implementations manually seemed tedious and complex.
The problem now is, that my queries are not very fast. An example is querying my ~200 users, and loading up their association (user.groups, user.groups.rights, user.groups.rights.permissions, user.rights, user.rights.permissions, users.nfc_keys). I need all this data because one of the clients connected to the Java Server needs this information to login users, even in case the main server goes down and also to speedup login (in other words, it caches the information).
The problem is, the query takes a whopping 8 seconds to perform! I'm aware of the problems, the n+1 problem to be specific. Because all my Collections are lazy loaded, hibernate queries the groups, groups.rights,.... individually for each user. For example my group field looks like this:
@ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
@JoinTable(
name = "user_group_memberships",
joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},
inverseJoinColumns={@JoinColumn(name="group_id", referencedColumnName="id")}
)
private List<Group> groups;
I tried changing FetchType to EAGER, the only thing this does is, fetch all the groups eagerly with the query, but not with an SQL-join, but again by doing n-queries.
I had a look at this blog post and implemented a query in the UserRepository loading the information using a LEFT JOIN FETCH, the needed to change from Lists to Sets, get annoyed about null pointer problems due to my hashCode/equals implementation and again lazy loading / set proxies, to find out that the query time was reduced to about 2 seconds, which is not bad, but still very slow compared to what CakePHP takes to do the same query.
My question now is mostly: Are there straightforward solutions to solve those kind of problems using Spring Data Repositories or am I better of switching to a different framework (which would be possible still in this early project phase)? I specifically looked at Ebeans used in the Play framework, and they seem to have a really nice API and also allow defining fetch paths (which should solve the n+1 problem much nicer), however I also read about the project being poorly maintained. What are your opinions?
Aucun commentaire:
Enregistrer un commentaire