小编典典

Spring Boot / JPA / mySQL-多对一关系创建了太多的SQL查询

spring-boot

我有一个与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 ?伪代码)

谢谢!


阅读 663

收藏
2020-05-30

共1个答案

小编典典

这可能是个n + 1问题。

您可以JOIN FETCH在JPA查询中使用来解决此问题。

“获取”联接允许使用单个选择将值的关联或集合及其父对象初始化。这在集合的情况下特别有用。它有效地覆盖了关联和集合的映射文件的外部联接和惰性声明。

像这样更新您的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: 我还没有测试查询。

2020-05-30