skip to Main Content

I am developing REST application using spring boot and I am trying to optimize the performance of the queries. I am currently using findById from the repositories which is causing performance issues. Code is given below:

User Entity

@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
@Entity
@Table(name="user", uniqueConstraints = @UniqueConstraint(columnNames = "email"))
@JsonIgnoreProperties({"comments"})
public class User implements UserDetails {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @NotEmpty(message = "first name should not be empty")
    @Column(name = "first_name")
    private String firstName;

    @NotEmpty(message = "last name should not be empty")
    @Column(name = "last_name")
    private String lastName;

    @Email(message = "Not a valid email")
    private String email;

    @NotEmpty
//    @Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[#$@!%&*?])[A-Za-z\d#$@!%&*?]{8,}$",
//            message ="1 Uppercase, 1 Lowercase, 1 special character, 1 number, Min 8 characters ")
    @Size(min = 8, message = "password should have at least 8 characters")
    private String password;

    @Enumerated(EnumType.STRING)
    private Role role;

    @OneToMany(mappedBy = "user",
            cascade = CascadeType.ALL)
    private Set<Comment> comments = new HashSet<>();

    @ManyToMany(mappedBy = "assignees")
    private Set<Issue> issues = new HashSet<>();

    @ManyToMany(mappedBy = "voters")
    private Set<Issue> votedIssues = new HashSet<>();

    @ManyToMany(mappedBy = "members")
    private Set<Community> communities = new HashSet<>();

    @ManyToMany(mappedBy = "requestingMembers")
    private Set<Community> requestedCommunities = new HashSet<>();

    @OneToMany(mappedBy = "admin", cascade = CascadeType.ALL)
    private Set<Community> communitiesCreated = new HashSet<>();

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return List.of(new SimpleGrantedAuthority(role.name()));
    }

    @Override
    public String getUsername() {
        return email;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

Issue Entity

@AllArgsConstructor
@Data
@Entity
@NoArgsConstructor
@Table(name="issue")
public class Issue {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String title;
    private String description;
    private LocalDate dateCreated;
    private boolean isOpen;

    @ManyToOne
    private User user;

    @OneToMany(mappedBy = "issue", cascade = CascadeType.ALL)
    private List<Comment> comments = new ArrayList<>();

    @ManyToMany(cascade = CascadeType.ALL)
    private List<User> voters = new ArrayList<>();

    @ManyToMany(cascade = CascadeType.ALL)
    private List<User> assignees = new ArrayList<>();

    @ManyToOne
    @JoinColumn(name = "community_id")
    private Community community;

}

Comment Entity


@AllArgsConstructor
@Data
@Entity
@NoArgsConstructor
@Table(name = "comment")
public class Comment {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String content;

    @ManyToOne
    private User user;

    @ManyToOne
    @JoinColumn(name = "issue_id")
    private Issue issue;

    private LocalDate dateCreated;
}

Role Enum

public enum Role {
    CUSTOMER("CUSTOMER"),
    EXPERT("EXPERT"),
    ADMIN("ADMIN");

    private String role;

    Role(String role) {
        this.role = role;
    }

    public String getRoleName() {
        return role;
    }
}

When I do a userRepository.findById(userId) there are so many select queries being fired. I am looking for a way to optimize the queries so that findById produces result in less queries. Currenlty it is making so many queries just for one api request for example :

2023-05-16T16:21:48.837+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from user u1_0 where u1_0.id=?
2023-05-16T16:21:48.911+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select i1_0.assignees_id,i1_1.id,c1_0.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_0.description,c1_0.name,i1_1.date_created,i1_1.description,i1_1.is_open,i1_1.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from issue_assignees i1_0 join issue i1_1 on i1_1.id=i1_0.issues_id left join community c1_0 on c1_0.id=i1_1.community_id left join user a1_0 on a1_0.id=c1_0.user_id left join user u1_0 on u1_0.id=i1_1.user_id where i1_0.assignees_id=?
2023-05-16T16:21:48.921+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select c1_0.user_id,c1_0.id,c1_0.content,c1_0.date_created,i1_0.id,c2_0.id,c2_0.user_id,c2_0.description,c2_0.name,i1_0.date_created,i1_0.description,i1_0.is_open,i1_0.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from comment c1_0 left join issue i1_0 on i1_0.id=c1_0.issue_id left join community c2_0 on c2_0.id=i1_0.community_id left join user u1_0 on u1_0.id=i1_0.user_id where c1_0.user_id=?
2023-05-16T16:21:48.927+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select c1_0.user_id,c1_0.id,c1_0.content,c1_0.date_created,i1_0.id,c2_0.id,c2_0.user_id,c2_0.description,c2_0.name,i1_0.date_created,i1_0.description,i1_0.is_open,i1_0.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from comment c1_0 left join issue i1_0 on i1_0.id=c1_0.issue_id left join community c2_0 on c2_0.id=i1_0.community_id left join user u1_0 on u1_0.id=i1_0.user_id where c1_0.user_id=?
2023-05-16T16:21:48.930+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select i1_0.assignees_id,i1_1.id,c1_0.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_0.description,c1_0.name,i1_1.date_created,i1_1.description,i1_1.is_open,i1_1.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from issue_assignees i1_0 join issue i1_1 on i1_1.id=i1_0.issues_id left join community c1_0 on c1_0.id=i1_1.community_id left join user a1_0 on a1_0.id=c1_0.user_id left join user u1_0 on u1_0.id=i1_1.user_id where i1_0.assignees_id=?
2023-05-16T16:21:48.932+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select v1_0.voters_id,v1_1.id,c1_0.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_0.description,c1_0.name,v1_1.date_created,v1_1.description,v1_1.is_open,v1_1.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from issue_voters v1_0 join issue v1_1 on v1_1.id=v1_0.voted_issues_id left join community c1_0 on c1_0.id=v1_1.community_id left join user a1_0 on a1_0.id=c1_0.user_id left join user u1_0 on u1_0.id=v1_1.user_id where v1_0.voters_id=?
2023-05-16T16:21:48.933+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select c1_0.members_id,c1_1.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_1.description,c1_1.name from community_members c1_0 join community c1_1 on c1_1.id=c1_0.communities_id left join user a1_0 on a1_0.id=c1_1.user_id where c1_0.members_id=?
2023-05-16T16:21:48.936+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select r1_0.requesting_members_id,r1_1.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,r1_1.description,r1_1.name from community_requesting_members r1_0 join community r1_1 on r1_1.id=r1_0.requested_communities_id left join user a1_0 on a1_0.id=r1_1.user_id where r1_0.requesting_members_id=?
2023-05-16T16:21:48.937+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select c1_0.user_id,c1_0.id,c1_0.description,c1_0.name from community c1_0 where c1_0.user_id=?
2023-05-16T16:21:48.938+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select m1_0.communities_id,m1_1.id,m1_1.email,m1_1.first_name,m1_1.last_name,m1_1.password,m1_1.role from community_members m1_0 join user m1_1 on m1_1.id=m1_0.members_id where m1_0.communities_id=?
2023-05-16T16:21:48.938+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select c1_0.user_id,c1_0.id,c1_0.content,c1_0.date_created,i1_0.id,c2_0.id,c2_0.user_id,c2_0.description,c2_0.name,i1_0.date_created,i1_0.description,i1_0.is_open,i1_0.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from comment c1_0 left join issue i1_0 on i1_0.id=c1_0.issue_id left join community c2_0 on c2_0.id=i1_0.community_id left join user u1_0 on u1_0.id=i1_0.user_id where c1_0.user_id=?
2023-05-16T16:21:48.940+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select c1_0.user_id,c1_0.id,c1_0.content,c1_0.date_created,i1_0.id,c2_0.id,c2_0.user_id,c2_0.description,c2_0.name,i1_0.date_created,i1_0.description,i1_0.is_open,i1_0.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from comment c1_0 left join issue i1_0 on i1_0.id=c1_0.issue_id left join community c2_0 on c2_0.id=i1_0.community_id left join user u1_0 on u1_0.id=i1_0.user_id where c1_0.user_id=?
2023-05-16T16:21:48.941+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select i1_0.assignees_id,i1_1.id,c1_0.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_0.description,c1_0.name,i1_1.date_created,i1_1.description,i1_1.is_open,i1_1.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from issue_assignees i1_0 join issue i1_1 on i1_1.id=i1_0.issues_id left join community c1_0 on c1_0.id=i1_1.community_id left join user a1_0 on a1_0.id=c1_0.user_id left join user u1_0 on u1_0.id=i1_1.user_id where i1_0.assignees_id=?
2023-05-16T16:21:48.942+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select v1_0.voters_id,v1_1.id,c1_0.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_0.description,c1_0.name,v1_1.date_created,v1_1.description,v1_1.is_open,v1_1.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from issue_voters v1_0 join issue v1_1 on v1_1.id=v1_0.voted_issues_id left join community c1_0 on c1_0.id=v1_1.community_id left join user a1_0 on a1_0.id=c1_0.user_id left join user u1_0 on u1_0.id=v1_1.user_id where v1_0.voters_id=?
2023-05-16T16:21:48.943+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select v1_0.voters_id,v1_1.id,c1_0.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_0.description,c1_0.name,v1_1.date_created,v1_1.description,v1_1.is_open,v1_1.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from issue_voters v1_0 join issue v1_1 on v1_1.id=v1_0.voted_issues_id left join community c1_0 on c1_0.id=v1_1.community_id left join user a1_0 on a1_0.id=c1_0.user_id left join user u1_0 on u1_0.id=v1_1.user_id where v1_0.voters_id=?
2023-05-16T16:21:48.944+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select c1_0.members_id,c1_1.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_1.description,c1_1.name from community_members c1_0 join community c1_1 on c1_1.id=c1_0.communities_id left join user a1_0 on a1_0.id=c1_1.user_id where c1_0.members_id=?
2023-05-16T16:21:48.945+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select m1_0.communities_id,m1_1.id,m1_1.email,m1_1.first_name,m1_1.last_name,m1_1.password,m1_1.role from community_members m1_0 join user m1_1 on m1_1.id=m1_0.members_id where m1_0.communities_id=?
2023-05-16T16:21:48.945+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select c1_0.user_id,c1_0.id,c1_0.description,c1_0.name from community c1_0 where c1_0.user_id=?
2023-05-16T16:21:48.946+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select i1_0.community_id,i1_0.id,i1_0.date_created,i1_0.description,i1_0.is_open,i1_0.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from issue i1_0 left join user u1_0 on u1_0.id=i1_0.user_id where i1_0.community_id=?
2023-05-16T16:21:48.947+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select r1_0.requesting_members_id,r1_1.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,r1_1.description,r1_1.name from community_requesting_members r1_0 join community r1_1 on r1_1.id=r1_0.requested_communities_id left join user a1_0 on a1_0.id=r1_1.user_id where r1_0.requesting_members_id=?
2023-05-16T16:21:48.947+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select c1_0.user_id,c1_0.id,c1_0.description,c1_0.name from community c1_0 where c1_0.user_id=?
2023-05-16T16:21:48.948+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select c1_0.user_id,c1_0.id,c1_0.content,c1_0.date_created,i1_0.id,c2_0.id,c2_0.user_id,c2_0.description,c2_0.name,i1_0.date_created,i1_0.description,i1_0.is_open,i1_0.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from comment c1_0 left join issue i1_0 on i1_0.id=c1_0.issue_id left join community c2_0 on c2_0.id=i1_0.community_id left join user u1_0 on u1_0.id=i1_0.user_id where c1_0.user_id=?
2023-05-16T16:21:48.949+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select i1_0.assignees_id,i1_1.id,c1_0.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_0.description,c1_0.name,i1_1.date_created,i1_1.description,i1_1.is_open,i1_1.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from issue_assignees i1_0 join issue i1_1 on i1_1.id=i1_0.issues_id left join community c1_0 on c1_0.id=i1_1.community_id left join user a1_0 on a1_0.id=c1_0.user_id left join user u1_0 on u1_0.id=i1_1.user_id where i1_0.assignees_id=?
2023-05-16T16:21:48.950+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select v1_0.voters_id,v1_1.id,c1_0.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_0.description,c1_0.name,v1_1.date_created,v1_1.description,v1_1.is_open,v1_1.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from issue_voters v1_0 join issue v1_1 on v1_1.id=v1_0.voted_issues_id left join community c1_0 on c1_0.id=v1_1.community_id left join user a1_0 on a1_0.id=c1_0.user_id left join user u1_0 on u1_0.id=v1_1.user_id where v1_0.voters_id=?
2023-05-16T16:21:48.951+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select c1_0.members_id,c1_1.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_1.description,c1_1.name from community_members c1_0 join community c1_1 on c1_1.id=c1_0.communities_id left join user a1_0 on a1_0.id=c1_1.user_id where c1_0.members_id=?
2023-05-16T16:21:48.951+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select r1_0.requesting_members_id,r1_1.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,r1_1.description,r1_1.name from community_requesting_members r1_0 join community r1_1 on r1_1.id=r1_0.requested_communities_id left join user a1_0 on a1_0.id=r1_1.user_id where r1_0.requesting_members_id=?
2023-05-16T16:21:48.952+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select c1_0.user_id,c1_0.id,c1_0.description,c1_0.name from community c1_0 where c1_0.user_id=?
2023-05-16T16:21:48.953+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select c1_0.user_id,c1_0.id,c1_0.content,c1_0.date_created,i1_0.id,c2_0.id,c2_0.user_id,c2_0.description,c2_0.name,i1_0.date_created,i1_0.description,i1_0.is_open,i1_0.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from comment c1_0 left join issue i1_0 on i1_0.id=c1_0.issue_id left join community c2_0 on c2_0.id=i1_0.community_id left join user u1_0 on u1_0.id=i1_0.user_id where c1_0.user_id=?
2023-05-16T16:21:48.953+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select i1_0.assignees_id,i1_1.id,c1_0.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_0.description,c1_0.name,i1_1.date_created,i1_1.description,i1_1.is_open,i1_1.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from issue_assignees i1_0 join issue i1_1 on i1_1.id=i1_0.issues_id left join community c1_0 on c1_0.id=i1_1.community_id left join user a1_0 on a1_0.id=c1_0.user_id left join user u1_0 on u1_0.id=i1_1.user_id where i1_0.assignees_id=?
2023-05-16T16:21:48.954+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select v1_0.voters_id,v1_1.id,c1_0.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_0.description,c1_0.name,v1_1.date_created,v1_1.description,v1_1.is_open,v1_1.title,u1_0.id,u1_0.email,u1_0.first_name,u1_0.last_name,u1_0.password,u1_0.role from issue_voters v1_0 join issue v1_1 on v1_1.id=v1_0.voted_issues_id left join community c1_0 on c1_0.id=v1_1.community_id left join user a1_0 on a1_0.id=c1_0.user_id left join user u1_0 on u1_0.id=v1_1.user_id where v1_0.voters_id=?
2023-05-16T16:21:48.954+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select c1_0.members_id,c1_1.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,c1_1.description,c1_1.name from community_members c1_0 join community c1_1 on c1_1.id=c1_0.communities_id left join user a1_0 on a1_0.id=c1_1.user_id where c1_0.members_id=?
2023-05-16T16:21:48.955+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select r1_0.requesting_members_id,r1_1.id,a1_0.id,a1_0.email,a1_0.first_name,a1_0.last_name,a1_0.password,a1_0.role,r1_1.description,r1_1.name from community_requesting_members r1_0 join community r1_1 on r1_1.id=r1_0.requested_communities_id left join user a1_0 on a1_0.id=r1_1.user_id where r1_0.requesting_members_id=?
2023-05-16T16:21:48.955+05:30 DEBUG 63236 --- [nio-8080-exec-1] org.hibernate.SQL                        : select c1_0.user_id,c1_0.id,c1_0.description,c1_0.name from community c1_0 where c1_0.user_id=? 

I am expecting just one or two select queries.

2

Answers


  1. First stop using @Data (or better Lombok all together) with JPA entities. When using @Data it will generate an equals/hashCode/toString method including all collections (which are lazy) in your entity. (I wrote a blog about it about 4 years ago and yet we still haven’t learned).

    Those hashCode and equals method are important as those are used to determine if an object is already in the cache or not. Now to calculate the hashCode what do you think will happen…. Exactly queries, queries and some more queries.

    I would suggest to create a BaseEntity which include a regular hashCode, equals and basic toString method. Then let all your entities extend this base class.

    Next replace the @Data with only @Getter/@Setter to generate the getters/setters.

    @MappedSuperclass
    @Getter
    public abstract BaseEntity {
    
      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      private Long id;
    
      @Override
      public int hashCode() {
        return getClass().hashCode();
      }
      
      @Override
      public boolean equals(Object o) {
        if (this == o) return true;
     
        if (getClass().isInstanceOf(o) && o instanceof BaseEntity other) {
          return this.id != null && Objects.equals(this.id, other.id);
        }
        return false;
      }
    
      @Override
      public String toString() {
        return String.format("%s [id=%d]", getClass().getSimpleName(), this.id);
      }  
    }
    

    Now for example let your Comment class extend this and drop the usage of @Data.

    @AllArgsConstructor
    @Getter
    @Setter
    @Entity
    @NoArgsConstructor
    @Table(name = "comment")
    public class Comment extends BaseEntity {
    
        private String content;
    
        @ManyToOne
        private User user;
    
        @ManyToOne
        @JoinColumn(name = "issue_id")
        private Issue issue;
    
        private LocalDate dateCreated;
    }
    

    This should already reduce the number of queries that are being issued. Another optimization you could do is to use bytecode enhancements to lazy load the Issue in the Comment (the sample ofcourse applies to other fields that can be lazy loaded). But this requires bytecode enhancements.

    Login or Signup to reply.
  2. I recommend avoiding the use of @Data (or preferably Lombok altogether) when working with JPA entities. When you use @Data, it generates methods such as equals, hashCode, and toString, which include all collections (which are lazy) in your entity. I wrote a blog about this issue around four years ago, yet it seems we still haven’t learned from it.

    These hashCode and equals methods are crucial as they are used to determine if an object is already present in the cache or not. Now, let’s consider what happens when calculating the hashCode… It results in queries, queries, and even more queries.

    To address this, I suggest creating a BaseEntity that includes a regular hashCode, equals, and a basic toString method. Then, have all your entities extend this base class.

    Additionally, replace @Data with only @Getter and @Setter annotations to generate the getters and setters.

    Here’s an example implementation:

    @MappedSuperclass
    @Getter
    public abstract class BaseEntity {
    
      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      private Long id;
    
      @Override
      public int hashCode() {
        return getClass().hashCode();
      }
      
      @Override
      public boolean equals(Object o) {
        if (this == o) return true;
     
        if (getClass().isInstance(o) && o instanceof BaseEntity other) {
          return this.id != null && Objects.equals(this.id, other.id);
        }
        return false;
      }
    
      @Override
      public String toString() {
        return String.format("%s [id=%d]", getClass().getSimpleName(), this.id);
      }  
    }
    

    Now, for example, let your Comment class extend this base class and remove the usage of @Data.

    @AllArgsConstructor
    @Getter
    @Setter
    @Entity
    @NoArgsConstructor
    @Table(name = "comment")
    public class Comment extends BaseEntity {
    
        private String content;
    
        @ManyToOne
        private User user;
    
        @ManyToOne
        @JoinColumn(name = "issue_id")
        private Issue issue;
    
        private LocalDate dateCreated;
    }
    

    This can help reduce the number of queries being issued. Another optimization option is to use bytecode enhancements for lazy loading specific fields, but it should be kept in mind that this approach requires bytecode enhancements.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search