JPA一对多关系重复数据问题导致的查询错误BeanSerializer

JPA重复数据问题:

两个实体类:

package com.itzhai.musicsystem.bean;

import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name=”t_user”)
public class User {
@Id
@Column(name = “user_id”)
private String username;
@Column(name = “user_nikename”, length=100)
private String nikename;
@Column(name = “user_password”, length=20)
private String password;
@Column(name = “user_email”, length=40)
private String email;
//@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, mappedBy = “creater”, fetch = FetchType.EAGER)
//单向一对多
@OneToMany(cascade = { CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.MERGE, CascadeType.REMOVE }, fetch = FetchType.EAGER, mappedBy = “creater”)
private Set albums;

public String getUsername() {
    return username;
}
public void setUsername(String username) {
    this.username = username;
}

public String getNikename() {
    return nikename;
}
public void setNikename(String nikename) {
    this.nikename = nikename;
}

public String getPassword() {
    return password;
}
public void setPassword(String password) {
    this.password = password;
}

public String getEmail() {
    return email;
}
public void setEmail(String email) {
    this.email = email;
}

public Set<Album> getAlbums() {
    return albums;
}
public void setAlbums(Set<Album> albums) {
    this.albums = albums;
}

}

package com.itzhai.musicsystem.bean;

import java.util.Date;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name=”t_album”)
public class Album {

@Id
@Column(name = "album_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int albumId=0;

@Column(name = "album_name", length=100)
private String albumName;

@Column(name = "album_createtime", length=20)
private Date createTime;

@ManyToOne(cascade = { CascadeType.REFRESH, CascadeType.MERGE }, optional = false)
@JoinColumn(name = "user_id")
private User creater;

//@Column(name = "album_musics")
//@OneToMany(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
@ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
@JoinTable(name = "t\_album\_t_music", 
        joinColumns = { @JoinColumn(name = "t\_album\_id", referencedColumnName = "album_id") },
        inverseJoinColumns = { @JoinColumn(name = "t\_music\_id", referencedColumnName = "music_id") })
private Set<Music> musics;

public int getAlbumId() {
    return albumId;
}
public void setAlbumId(int albumId) {
    this.albumId = albumId;
}

public String getAlbumName() {
    return albumName;
}
public void setAlbumName(String albumName) {
    this.albumName = albumName;
}

public Date getCreateTime() {
    return createTime;
}
public void setCreateTime(Date createTime) {
    this.createTime = createTime;
}

public User getCreater() {
    return creater;
}
public void setCreater(User creater) {
    this.creater = creater;
}

public Set<Music> getMusics() {
    return musics;
}
public void setMusics(Set<Music> musics) {
    this.musics = musics;
}

}

使用Jackson框架转换:

ObjectMapper objectMapper = new ObjectMapper();
JsonGenerator jsonGenerator = null;
String result;
try {
    jsonGenerator = objectMapper.getJsonFactory().createJsonGenerator(System.out, JsonEncoding.UTF8);
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

QueryResult<Album> albumList = new QueryResult<Album>();
albumList = ManagerHelper.getAlbumManager().getScrollData(Album.class);

try {
    jsonGenerator.writeObject(albumList.getResultlist());
} catch (JsonProcessingException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

发现得出如下的数据:

[{“albumId”:1,”musics”:[{“id3v1”:”TAG”,”songName”:”红日\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000”,”artist”:”李克勤\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000”,”album”:”留住这一刻-李克勤1\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000”,”genre”:0,”musicUrl”:”http://localhost/music/李克勤-红日.mp3","id":7,"size":4643195,"comment":"\\u0000\\u0001\\f “,”year”:”\u0000\u0000\u0000\u0000”}],”albumName”:”abcdefg”,”createTime”:1335692164000,”creater”:{“username”:”arthinking”,”nikename”:”abc”,”email”:”arthinking@qq.com“,”albums”:[{“albumId”:2,”musics”:[{“id3v1”:”TAG”,”songName”:”千千厥歌\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000”,”artist”:”陳慧嫻\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000”,”album”:”柔情金曲精装集\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000”,”genre”:0,”musicUrl”:”http://localhost/music/陈慧娴 - 千千厥歌.mp3”,”id”:15,”size”:8436425,”comment”:”\u0000\u0000?\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000”,”year”:”\u0000\u0000\u0000\u0000”}],”albumName”:”gggggsfeffs”,”createTime”:1335693885000,”creater”:{“username”:”arthinking”,”nikename”:”abc”,”email”:”arthinking@qq.com“,”albums”:[{“albumId”:2,”musics”:[{“id3v1”:”TAG”,”songName”:”千千厥歌\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000”,”artist”:”陳慧嫻\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000”,”album”:”柔情金曲精装集\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000”,”genre”:0,”musicUrl”:”http://localhost/music/陈慧娴 - 千千厥歌.mp3”,”id”:15,”size”:8436425,”comment”:”\u0000\u0000?\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000”,”year”:”\u0000\u0000\u0000\u0000”}],”albumName”:”gggggsfeffs”,”createTime”:1335693885000,”creater”:{“username”:”arthinking”,”nikename”:”abc”,”email”:”arthinking@qq.com“,”albums”:[{“albumId”:2,”musics”:[{“id3v1”:”TAG”,”songName”:”千千厥歌\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000”,”artist”:”陳慧嫻\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000”,”album”:”柔情金曲精装集\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000”,”genre”:0,”musicUrl”:”http://localhost/music/陈慧娴 - 千千厥歌.mp3”,”id”:15,”size”:8436425,”comment”:”\u0000\u0000?\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000”,”year”:”\u0000\u0000\u0000\u0000”}],”albumName”:”gggggsfeffs”,”createTime”:1335693885000,”creater”:{“username”:”arthinking”,”nikename”:”abc”,”email”:”arthinking@qq.com“,此处省略n个字

之后便是一直报错:

at org.codehaus.jackson.map.ser.BeanSerializer.serializeFields(BeanSerializer.java:175)

从输出的结果可以看出是查处了不断重复的数据。

经过进一步分析发现上面的数据中Album中的creater里面又有Album,这样不断的重复获取数据,就形成了无限循环。

为了解决这个问题,就是让use成为维护端,这样从user这边查出的所有Album就不会重复了。

或者改成由Album到user的多对一关系,而不是由create到Album的一对多关系,既是把user中的album集合删除,Album成为维护端:

保留Album中的配置即可,这样就可以从Album端查出数据了。生成的表只是在t_album加了个user_id外键。

根据表的模型进行配置,不要为了ORM而ORM。根据自己的需要选择合理的配置和查询方法,这样才能写出高效的查询代码。根据自己的表的设计,查阅到到相关的配置方法进行配置,这样才能从本质上提高自己的数据库设计能力。

arthinking wechat
欢迎关注itzhai公众号