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

时间:2017-05-28 06:55:44

标签: java mysql hibernate jpa spring-boot

我有一个简单的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 Log - 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 ?(伪代码)

谢谢!

1 个答案:

答案 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:我没有测试过该查询。