2017-05-28 55 views
1

我有一个MySQL数据库连接的简单的弹簧启动其余应用程序,我想简单的优化函数中的查询号码:春季启动/ JPA/MySQL的 - 多对一的关系产生太多的SQL查询

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; 
} 

上层执行上述方法后,休眠产生约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 ?(伪代码)

谢谢!

回答

2

这可能是一个n + 1问题。

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

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

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); 

} 

更新您的JPA库对于更详细的解释退房this答案。

PS:我还没有测试过查询。

+0

作品像魅力,谢谢! – Jacek

+0

很高兴帮助! Upvote并接受答案! –

+0

“感谢您的反馈!记录下名声不到15的人的投票记录,但不要更改公开显示的帖子分数。” ;-)无论如何,你的答案被接受:-) – Jacek