我有一个与mySQL db连接的简单的spring boot rest应用程序,我试图在简单的函数内优化查询数量:
List<Message> messages = messagesRepository.findBySenderIdOrReceiverIdOrderByTimeDesc(senderId, receiverId);
消息存储库:
public interface MessagesRepository extends CrudRepository<Message, Long> { List<Message> findBySenderIdOrReceiverIdOrderByTimeDesc(Long senderId, Long receiverId); }
信息:
@Entity @Table(name="s_messages") public class Message implements Serializable { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; @Transient private int internalId; @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name="senderId", referencedColumnName = "id", updatable=false, insertable=false) private ProfileLite sender; @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name="receiverId", referencedColumnName = "id", updatable=false, insertable=false) private ProfileLite receiver; @Column(columnDefinition="TEXT") private String message; private long time; private MessageStatus status; }
ProfileLite:
@Entity @Table(name="s_profiles") public class ProfileLite implements Comparable<ProfileLite> { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; private String nickname; private String country; private String thumb; private Gender gender; }
执行完上述方法后,hibernate会生成大约40个SQL(基于40个配置文件),如下所示:
SQL日志-PasteBin
因此,首先收集消息,然后为每条消息创建另一个sql以收集配置文件。
是否有可能将hibernate推送为仅创建一个简单的sql而不是40,例如:(select * from s_messages m join s_profiles s1 on m.sender_id = s1.id join s_profiles s2 m_receiver_id = s2.id ?伪代码)
select * from s_messages m join s_profiles s1 on m.sender_id = s1.id join s_profiles s2 m_receiver_id = s2.id ?
谢谢!
这可能是个n + 1问题。
n + 1
您可以JOIN FETCH在JPA查询中使用来解决此问题。
JOIN FETCH
“获取”联接允许使用单个选择将值的关联或集合及其父对象初始化。这在集合的情况下特别有用。它有效地覆盖了关联和集合的映射文件的外部联接和惰性声明。
像这样更新您的JPA存储库
public interface MessagesRepository extends CrudRepository<Message, Long> { @Query("Select m from Message m join fetch m.sender ms join fetch m.receiver mr where ms.id = :senderId or mr.id = :receiverId order by m.time desc") List<Message> findBySenderIdOrReceiverIdOrderByTimeDesc(Long senderId, Long receiverId); }
PS: 我还没有测试查询。