【问题标题】:Spring Boot / JPA / mySQL - many to one relationship creates too many SQL queriesSpring Boot / JPA / mySQL - 多对一关系创建太多 SQL 查询
【发布时间】:2017-10-28 16:58:29
【问题描述】:

我有一个与 mySQL db 连接的简单 spring boot rest 应用程序,我正在尝试优化简单函数中的查询数量:

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 ?(伪代码)

谢谢!

【问题讨论】:

    标签: java mysql hibernate jpa spring-boot


    【解决方案1】:

    这可能是n + 1 问题。

    您可以在 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);
    
    }
    

    如需更详细的解释,请查看this 答案。

    PS:我没有测试查询。

    【讨论】:

    • "感谢您的反馈!声望低于 15 人的投票将被记录,但不要更改公开显示的帖子得分。" ;-) 无论如何,你的答案被接受:-)
    猜你喜欢
    • 2020-03-29
    • 2019-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多