当我尝试进行 JPQL JOIN 查询时发生 ***Error

Posted

技术标签:

【中文标题】当我尝试进行 JPQL JOIN 查询时发生 ***Error【英文标题】:The ***Error occurs when I try to make JPQL JOIN query 【发布时间】:2019-02-27 11:40:20 【问题描述】:

我有以下实体:

@Data
@Entity
@Table(name = "artist")
public class Artist 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="artist_id")
    private int id;
    @Column(name="artist_name", length = 2000)
    private String name;
    private String country;
    @OneToMany(mappedBy = "artist", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private List<Song> songs = new ArrayList<>();

    public Artist(String name, String country)
        this.name=name;
        this.country=country;
    


@Data
@Entity
@Table(name = "songs")
public class Song 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int songId;
    @Column(name = "text", length = 65600)
    private String text;
    private Double rating;
    private String songName;
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "artist_id", nullable = false)
    public Artist artist;

    public Song(String text, Double rating, String songName, Artist artist) 
        this.text = text;
        this.rating = rating;
        this.songName = songName;
        this.artist = artist;
    

我尝试按艺术家姓名模式获取所有歌曲:

@Query("SELECT s FROM Song s WHERE s.artist.name LIKE CONCAT('%',:name,'%')") List findByArtistsName(@Param("name") String name);

以及所有歌手的歌曲名称模式:

@Query("SELECT a FROM Artist a JOIN FETCH a.songs s WHERE s.songName LIKE CONCAT('%',:pattern,'%')")
List<Artist> findBySong(@Param("pattern") String songName);

为此,我分别使用该 JPQL 查询。但两者都让我一样 堆栈溢出错误。

> 
> 
>     Caused by: java.lang.***Error: null
>       at sun.misc.FloatingDecimal$BinaryToASCIIBuffer.dtoa(FloatingDecimal.java:431)
> ~[na:1.8.0_151]
>       at sun.misc.FloatingDecimal$BinaryToASCIIBuffer.access$100(FloatingDecimal.java:259)
> ~[na:1.8.0_151]
>       at sun.misc.FloatingDecimal.getBinaryToASCIIConverter(FloatingDecimal.java:1785)
> ~[na:1.8.0_151]
>       at sun.misc.FloatingDecimal.getBinaryToASCIIConverter(FloatingDecimal.java:1738)
> ~[na:1.8.0_151]
>       at sun.misc.FloatingDecimal.toJavaFormatString(FloatingDecimal.java:70)
> ~[na:1.8.0_151]
>       at java.lang.Double.toString(Double.java:204) ~[na:1.8.0_151]
>       at java.lang.Double.toString(Double.java:644) ~[na:1.8.0_151]
>       at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_151]
>       at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_151]
>       at com.music.entity.Song.toString(Song.java:8) ~[classes/:na]
>       at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_151]
>       at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_151]
>       at java.util.AbstractCollection.toString(AbstractCollection.java:462)
> ~[na:1.8.0_151]
>       at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:510)
> ~[hibernate-core-5.2.17.Final.jar:5.2.17.Final]
>       at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_151]
>       at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_151]
>       at com.music.entity.Artist.toString(Artist.java:9) ~[classes/:na]
>       at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_151]
>       at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_151]
>       at com.music.entity.Song.toString(Song.java:8) ~[classes/:na]
>       at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_151]
>       at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_151]
>       at java.util.AbstractCollection.toString(AbstractCollection.java:462)
> ~[na:1.8.0_151]

解决这个问题的正确方法是什么?

【问题讨论】:

【参考方案1】:

这几乎可以肯定是由于您使用了Lombok 和@Data 注释,这是其他Lombok 注释的快捷方式:

@ToString、@EqualsAndHashCode、@Getter 用于所有字段,@Setter 用于所有非最终字段,@RequiredArgsConstructor

@ToString 注释会自动生成一个包含所有字段的toString 方法。堆栈跟踪的底部指向集合上的 toString 方法调用,如果您按照堆栈向上,您可以发现导致堆栈溢出的循环:

AbstractCollection.toString -> Song.toString -> Artist.toString -> AbstractCollection.toString -> Song.toString ...

您的Artist 实体包含Song 实体的集合,其中包含对Artist 实体的引用,依此类推。您可以看到它是如何在调用toString 方法时陷入循环并最终耗尽堆栈帧/达到限制的。

要么删除@Data 注释并仅应用一个子集,要么定义您自己的避免循环的toString 方法。

【讨论】:

是的,这是真的。谢谢,你的回答很有帮助!

以上是关于当我尝试进行 JPQL JOIN 查询时发生 ***Error的主要内容,如果未能解决你的问题,请参考以下文章

JPQL JOIN 查询对应值的行数(多列)

JPQL 查询删除不接受声明的 JOIN?

如何在一个 JPQL 查询中使用多个 JOIN FETCH

使用 JPQL 通过连接表进行查询时出错

JPQL 中的 LEFT JOIN ON()

JPQL 外键查询