如何解决Spring JPA 存储库 n+1 问题,如何将 n+1 选择减少为 1?
我的 JPA 存储库有问题。我有实体:
@Getter
@Setter
@Entity
@NamedEntityGraph(name = "user-graph",includeAllAttributes = true,attributeNodes = {
@NamedAttributeNode("recruiter")
})
@Table(name = "users")
public class User extends BaseEntity implements Serializable,UserDetails {
private static final long serialVersionUID = 1L;
private String name;
private String lastName;
@Column(nullable = false,unique = true)
private String username;
private String dateOfBirth;
private String phone;
private String facebook;
private String twitter;
private String instagram;
private String description;
private Long experience;
@Column(columnDeFinition = "boolean default false")
private boolean possibleRelocation;
@Column(columnDeFinition = "boolean default false")
private boolean remote;
private boolean emailVisible;
@Column(nullable = false)
private String password;
private boolean enabled;
private boolean isExpired;
private boolean isLocked;
private boolean isCredentialsExpired;
private boolean isSuperAdmin;
@OnetoMany(mappedBy = "user",fetch = FetchType.LAZY)
private Set<RecruiterFavouriteUsers> recruiterFavouriteUsers = new HashSet<>();
@Transient
@JsonIgnore
@Column(nullable = false)
private String passwordConfirm;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "role_id",referencedColumnName = "id",nullable = false)
private Role role;
@OnetoOne(mappedBy = "user")
private VerificationToken verificationToken;
@OnetoOne(fetch = FetchType.LAZY)
@JoinColumn(name = "company_id")
private Company company;
@OnetoOne
@JoinColumn(name = "recruiter_id")
private Recruiter recruiter;
@OnetoOne(fetch = FetchType.LAZY)
@JoinColumn(name = "address_id")
private Address address;
@OnetoOne(fetch = FetchType.LAZY)
@JoinColumn(name = "avatar_id")
private Avatar avatar;
@OnetoOne(fetch = FetchType.LAZY)
@JoinColumn(name = "background_id")
private Background background;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "position_level_id",referencedColumnName = "id")
private PositionLevelDict positionLevel;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "workplace_id",referencedColumnName = "id")
private WorkplaceDict workplace;
@OnetoMany(mappedBy = "user",fetch = FetchType.LAZY)
private Set<Skill> skill;
@OnetoMany(mappedBy = "user",fetch = FetchType.LAZY)
private Set<Language> language;
@OnetoMany(mappedBy = "user",fetch = FetchType.LAZY)
private Set<Work> work;
@OnetoMany(mappedBy = "user",fetch = FetchType.LAZY)
private Set<School> school;
@OnetoMany(mappedBy = "userTo",fetch = FetchType.LAZY)
private Set<MessageGroup> messageGroupsTo;
@OnetoMany(mappedBy = "userFrom",fetch = FetchType.LAZY)
private Set<MessageGroup> messageGroupsFrom;
...
}
和存储库:
@Repository
@Transactional
public interface UserRepository extends JpaRepository<User,Long>,JpaSpecificationExecutor<User> {
@EntityGraph("user-graph")
Optional<User> findById(Long id);
@EntityGraph("user-graph")
User findByUsername(String username);
@EntityGraph("user-graph")
User findByUsernameAndEnabledTrue(String username);
@EntityGraph("user-graph")
User findByUsernameAndEnabledFalse(String username);
}
当我尝试使用 findById 方法时,我遇到了 n+1 问题:
Hibernate:选择 user0_.id 作为 id1_32_0_,user0_.create_date 作为 create_d2_32_0_,user0_.last_update as last_upd3_32_0_,user0_.address_id 为 address23_32_0_,user0_.avatar_id 为 avatar_24_32_0_,user0_.background_id 作为 backgro25_32_0_, user0_.company_id 为 company26_32_0_,user0_.date_of_birth 为 date_of_4_32_0_,user0_.description as descript5_32_0_,user0_.email_visible 为 email_vi6_32_0_,user0_.enabled 为 enabled7_32_0_,user0_.experience as experien8_32_0_,user0_.facebook 作为 facebook9_32_0_,user0_.instagram 作为 instagr10_32_0_, user0_.is_credentials_expired 为 is_cred11_32_0_,user0_.is_expired 为 is_expi12_32_0_,user0_.is_locked as is_lock13_32_0_,user0_.is_super_admin as is_supe14_32_0_,user0_.last_name as last_na15_32_0_,user0_.name as name16_32_0_,user0_.password as passwor17_32_0_,user0_.phone 作为 phone18_32_0_,user0_.position_level_id 为 positio27_32_0_, user0_.possible_relocation 为 possibl19_32_0_,user0_.recruiter_id 为 Recruit28_32_0_,user0_.remote 为 remote20_32_0_,user0_.role_id 为 role_id29_32_0_,user0_.twitter 为 twitter21_32_0_,user0_.username 为 usernam22_32_0_,user0_.workplace_id 作为 workpla30_32_0_,address1_.id 作为 id1_0_1_,address1_.create_date 作为 create_d2_0_1_, address1_.last_update 为 last_upd3_0_1_,address1_.city 为 city4_0_1_, address1_.country 为 country5_0_1_,address1_.flat_number 为 flat_num6_0_1_,address1_.house_number 为 house_nu7_0_1_, address1_.post_code 为 post_cod8_0_1_,address1_.street 为 street9_0_1_,avatar2_.id 为 id1_1_2_,avatar2_.create_date 为 create_d2_1_2_,avatar2_.last_update 为 last_upd3_1_2_,avatar2_.image 作为 image4_1_2_,avatar2_.mimetype 作为 mimetype5_1_2_,avatar2_.name 作为 name6_1_2_,background3_.id 为 id1_2_3_,background3_.create_date 为 create_d2_2_3_,background3_.last_update 为 last_upd3_2_3_, background3_.image 为 image4_2_3_,background3_.mimetype 为 mimetype5_2_3_,background3_.name as name6_2_3_,company4_.id as id1_3_4_,company4_.create_date 为 create_d2_3_4_, company4_.last_update 为 last_upd3_3_4_, company4_.company_creation_date 为 company_4_3_4_, company4_.company_size_id 为 company_7_3_4_,company4_.description 为 descript5_3_4_,company4_.name as name6_3_4_,language5_.user_id as user_id7_23_5_,language5_.id 为 id1_23_5_,language5_.id 为 id1_23_6_,language5_.create_date 为 create_d2_23_6_,language5_.last_update 为 last_upd3_23_6_,language5_.company_id 为 company_6_23_6_,language5_.level as level4_23_6_,language5_.name as name5_23_6_,language5_.user_id 为 user_id7_23_6_, messagegro6_.user_from_id 为 user_fro6_25_7_,messagegro6_.id 为 id1_25_7_,messagegro6_.id 为 id1_25_8_,messagegro6_.create_date 为 create_d2_25_8_,messagegro6_.last_update 为 last_upd3_25_8_,messagegro6_.deleted_user_id 为deleted_4_25_8_, messagegro6_.last_message 为 last_mes5_25_8_, messagegro6_.user_from_id 作为 user_fro6_25_8_,messagegro6_.user_to_id 作为 user_to_7_25_8_,messagegro7_.user_to_id 作为 user_to_7_25_9_, messagegro7_.id 为 id1_25_9_,messagegro7_.id 为 id1_25_10_, messagegro7_.create_date 为 create_d2_25_10_,messagegro7_.last_update 如last_upd3_25_10_,messagegro7_.deleted_user_id 为deleted_4_25_10_, messagegro7_.last_message 为 last_mes5_25_10_, messagegro7_.user_from_id 作为 user_fro6_25_10_,messagegro7_.user_to_id 作为 user_to_7_25_10_,positionle8_.id 作为 id1_14_11_, positionle8_.create_date 为 create_d2_14_11_,positionle8_.last_update as last_upd3_14_11_,positionle8_.name as name4_14_11_,recruiter9_.id 作为 id1_27_12_,recruiter9_.create_date 作为 create_d2_27_12_, Recruiter9_.last_update 为 last_upd3_27_12_,recruiter9_.payment_id 为 付款_4_27_12_,recruiter9_.recruiter_type_id 为recruite5_27_12_, Recruiterf10_.user_id 为 user_id5_28_13_,recruiterf10_.id 为 id1_28_13_,recruiterf10_.id 为 id1_28_14_,recruiterf10_.create_date 作为 create_d2_28_14_,recruiterf10_.last_update 作为 last_upd3_28_14_, 招聘人员f10_.recruiter_id 为recruite4_28_14_、recruiterf10_.user_id 作为 user_id5_28_14_,role11_.id 作为 id1_29_15_,role11_.create_date 作为 create_d2_29_15_,role11_.last_update 为 last_upd3_29_15_, role11_.name 为 name4_29_15_,school12_.user_id 为 user_id9_30_16_, school12_.id 为 id1_30_16_,school12_.id 为 id1_30_17_, school12_.create_date 为 create_d2_30_17_,school12_.last_update 为 last_upd3_30_17_,school12_.end_year 为 end_year4_30_17_,school12_.field_of_study 为 field_of5_30_17_,school12_.name 为 name6_30_17_,school12_.start_year 为 start_ye7_30_17_,school12_.title 为 title8_30_17_,school12_.user_id 为 user_id9_30_17_,skill13_.user_id 为 user_id7_31_18_,skill13_.id 为 id1_31_18_,skill13_.id 为 id1_31_19_,skill13_.create_date 为 create_d2_31_19_,skill13_.last_update 为 last_upd3_31_19_, Skill13_.company_id 为 company_5_31_19_,skill13_.level 为 level4_31_19_,skill13_.technology_id 为 technolo6_31_19_, Skill13_.user_id 为 user_id7_31_19_,work14_.user_id 为 user_id14_34_20_,work14_.id 为 id1_34_20_,work14_.id 为 id1_34_21_, work14_.create_date 为 create_d2_34_21_,work14_.last_update 为 last_upd3_34_21_,work14_.city 为 city4_34_21_,work14_.company_name 作为 company_5_34_21_,work14_.country 作为 country6_34_21_, work14_.description 为 descript7_34_21_,work14_.end_month 为 end_mont8_34_21_,work14_.end_year 为 end_year9_34_21_, work14_.start_month 为 start_m10_34_21_,work14_.start_year 为 start_y11_34_21_,work14_.still_working as still_w12_34_21_,work14_.user_id 为 user_id14_34_21_,work14_.workplace 为 workpla13_34_21_,workplaced15_.id 为 id1_17_22_, 工作场所d15_.create_date 为create_d2_17_22_, Workplaced15_.last_update 为 last_upd3_17_22_,workplaced15_.name 为 name4_17_22_,verificati16_.id 为 id1_33_23_, verificati16_.create_date 为 create_d2_33_23_, verificati16_.last_update 为 last_upd3_33_23_,verificati16_.enabled 作为启用4_33_23_,verificati16_.expiry_date 作为expiry_d5_33_23_, verificati16_.token 作为 token6_33_23_,verificati16_.user_id 作为 user_id8_33_23_,verificati16_.verification_token 作为 verifica7_33_23_ 从用户 user0_ 左外连接地址 address1_ 上 user0_.address_id=address1_.id 左外加入 avatar avatar2_ on user0_.avatar_id=avatar2_.id 左外加入背景 background3_ 在 user0_.background_id=background3_.id 上离开外部加入公司 company4_ on user0_.company_id=company4_.id 左外连接语言 language5_ on user0_.id=language5_.user_id 左外连接 message_group messagegro6_ on user0_.id=messagegro6_.user_from_id left 外加入message_group messagegro7_ on user0_.id=messagegro7_.user_to_id 左外连接 d_position_level positionle8_ on user0_.position_level_id=positionle8_.id 左外 加入招聘人员recruiter9_ on user0_.recruiter_id=recruiter9_.id left 外部加入Recruiter_favourite_usersRecruiterf10_ on user0_.id=recruiterf10_.user_id 内连接角色 role11_ on user0_.role_id=role11_.id 离开outer join school school12_ on user0_.id=school12_.user_id 左外连接技能 Skill13_ on user0_.id=skill13_.user_id 左外连接工作 work14_ on user0_.id=work14_.user_id 左外连接 d_workplaceworkplaced15_ on user0_.workplace_id=workplaced15_.id 左外连接 verify_token verificati16_ on user0_.id=verificati16_.user_id 哪里 user0_.id=?休眠:选择recruiter0_.id 作为id1_27_0_, Recruiter0_.create_date 为 create_d2_27_0_,recruiter0_.last_update 为 last_upd3_27_0_,recruiter0_.payment_id 作为 payment_4_27_0_, 招聘人员0_.recruiter_type_id 为recruite5_27_0_,user1_.id 为 id1_32_1_,user1_.create_date 为 create_d2_32_1_,user1_.last_update 作为last_upd3_32_1_,user1_.address_id 作为address23_32_1_, user1_.avatar_id 为 avatar_24_32_1_,user1_.background_id 为 backgro25_32_1_,user1_.company_id 为 company26_32_1_, user1_.date_of_birth 为 date_of_4_32_1_,user1_.description 为 descript5_32_1_,user1_.email_visible as email_vi6_32_1_,user1_.enabled as enabled7_32_1_,user1_.experience as experien8_32_1_,user1_.facebook 为 facebook9_32_1_,user1_.instagram 如 instagr10_32_1_,user1_.is_credentials_expired 为 is_cred11_32_1_, user1_.is_expired 为 is_expi12_32_1_,user1_.is_locked 为 is_lock13_32_1_,user1_.is_super_admin as is_supe14_32_1_,user1_.last_name 为 last_na15_32_1_,user1_.name 为 name16_32_1_, user1_.password 为 passwor17_32_1_,user1_.phone 为 phone18_32_1_, user1_.position_level_id 为 positio27_32_1_, user1_.possible_relocation 为 possibl19_32_1_,user1_.recruiter_id 为 Recruit28_32_1_,user1_.remote 为 remote20_32_1_,user1_.role_id 为 role_id29_32_1_,user1_.twitter 为 twitter21_32_1_,user1_.username 为 usernam22_32_1_,user1_.workplace_id 为 workpla30_32_1_, verificati2_.id 为 id1_33_2_,verificati2_.create_date 为 create_d2_33_2_,verificati2_.last_update 为 last_upd3_33_2_,verificati2_.enabled 为 enabled4_33_2_,verificati2_.expiry_date 为 expiry_d5_33_2_,verificati2_.token 作为 token6_33_2_, verificati2_.user_id 为 user_id8_33_2_, verificati2_.verification_token 作为 verifica7_33_2_ 来自招聘人员 招聘人员 0_ 左外加入用户 user1_ 上 Recruiter0_.id=user1_.recruiter_id 左外加入验证_token verificati2_ 在 user1_.id=verificati2_.user_id 上,其中recruiter0_.id=? 休眠:选择 technology0_.id 作为 id1_16_0_, technology0_.create_date 为 create_d2_16_0_,technology0_.last_update as last_upd3_16_0_,technology0_.name as name4_16_0_ from d_technology 技术0_在哪里技术0_.id=?休眠:选择 technology0_.id 作为 id1_16_0_,technology0_.create_date 作为 create_d2_16_0_,technology0_.last_update as last_upd3_16_0_,technology0_.name as name4_16_0_ 来自 d_technology technology0_ where technology0_.id=? 休眠:选择 technology0_.id 作为 id1_16_0_, technology0_.create_date 为 create_d2_16_0_,technology0_.name as name4_16_0_ from d_technology technology0_ where technology0_.id=?
如何将所有这些选择减少到一个?
其他实体:
@Data
@Entity
public class VerificationToken extends BaseEntity {
private String token;
@OnetoOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
private boolean verificationToken;
private boolean enabled;
private Date expiryDate;
@Getter
@Setter
@Entity
@Table(name = "recruiter")
public class Recruiter extends BaseEntity {
@OnetoOne(mappedBy = "recruiter")
private User user;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "recruiter_type_id",referencedColumnName = "id")
private RecruiterTypeDict recruiterType;
@OnetoOne(fetch = FetchType.LAZY)
@JoinColumn(name = "payment_id")
private Payment payment;
@OnetoMany(mappedBy = "recruiter")
private Set<RecruiterFavouriteUsers> recruiterFavouriteUsers = new HashSet<>();
}
@Entity
@Getter
@Setter
@Table(name = "skill")
public class Skill extends BaseEntity {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "technology_id",nullable = false)
private TechnologyDict technology;
@Column(nullable = false)
private Long level;
@ManyToOne
@JoinColumn(name = "user_id",referencedColumnName = "id")
private User user;
@ManyToOne
@JoinColumn(name = "company_id",referencedColumnName = "id")
private Company company;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。