我有一个简单的spring boot rest应用程序与mySQL db连接,我正在尝试在简单函数中优化查询数量:
List<Message> messages = messagesRepository.findBySenderIdOrReceiverIdOrderByTimeDesc(senderId, receiverId);
MessagesRepository:
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以收集配置文件。
是否有可能推动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 ?
(伪代码)
谢谢!
答案 0 :(得分:2)
这可能是n + 1
问题。
您可以在JPA查询中使用JOIN FETCH
来解决此问题。
A&#34; fetch&#34; join允许使用单个select将关联或值集合与其父对象一起初始化。这在集合的情况下特别有用。它有效地覆盖了关联和集合的映射文件的外连接和延迟声明。
像这样更新您的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);
}
有关更详细的说明,请查看this answer。
PS:我没有测试过该查询。