早上好,很高兴见到你。
我最近刚接触Spring Boot,我正在使用REST API,它基本上是一个包含歌曲的播放列表,基本上REST API应该具有以下结构。一个播放列表可以有许多歌曲:
{
"name": "Lista 1",
"description": "Lista de reproduccion 2020 spotify",
"songs": [
{
"title": "Tan Enamorados",
"artist": "CNCO",
"album": "Tan Enamorados",
"year": 2020,
"playList": 1
},
{
"title": "Hawai",
"artist": "Maluma",
"album": "PAPI JUANCHO",
"year": 2020,
"playList": 1
}
]
}
目前,这是我配置实体的方式
实体歌曲
@Entity
@Table(name = "SONGS")
public class Songs{
@JsonIgnore
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "ID")
private Long id;
@Column(name = "title")
private String title;
@Column(name = "artist")
private String artist;
@Column(name = "album")
private String album;
@Column(name = "year")
private int year;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "PLAY_LIST_ID")
private PlayList playList;
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
public String getArtist() {
return this.artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
public String getAlbum() {
return this.album;
}
public void setAlbum(String album) {
this.album = album;
}
public int getYear() {
return this.year;
}
public void setYear(int year) {
this.year = year;
}
public PlayList getPlayList() {
return this.playList;
}
public void setPlayList(PlayList playList) {
this.playList = playList;
}
}
实体播放列表
@Entity
@Table(name = "PLAY_LIST")
public class PlayList {
@JsonIgnore
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "ID")
private Long id;
@Column(name="name")
private String name;
@Column(name="description")
private String description;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true, mappedBy = "playList")
private List<Songs> songs = new ArrayList<>();
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
public List<Songs> getSongs() {
return this.songs;
}
public void setSongs(List<Songs> songs) {
this.songs = songs;
}
}
控制器
@RestController
@RequestMapping("playlist")
public class PlayListController {
@Autowired
private PlayListService playListService;
//Get playlist by id with songs belongs that playlist
@GetMapping("/{id}")
public Optional<PlayList> getPlayListByID(@PathVariable(value = "id") Long id) {
Optional<PlayList> playList = playListService.getById(id);
return playList;
}
@PostMapping("/create")
public PlayList createPlayList(@RequestBody PlayList playList) {
return playListService.savePlayList(playList);
}
}
我的班级播放列表
@Service
public class PlayListServiceImpl implements PlayListService {
@Autowired
private PlayListRepository playListRepository;
public Optional <PlayList> getById(Long Id) {
Optional <PlayList> playList= playListRepository.findById(Id);
return playList;
}
@Override
public PlayList savePlayList(PlayList playList) {
return playListRepository.save(playList);
}
}
我的资源库
@Repository
public interface PlayListRepository extends JpaRepository<PlayList, Long> {
Optional<PlayList> findById(Long Id);
}
但是,当我尝试使用get方法获取播放列表时,我遇到了无限递归问题:
org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: com.example.api.songs.entity.PlayList[\"songs\"]->org.hibernate.collection.internal.PersistentBag[0]->com.example.api.songs.entity.Songs[\"playList\"]->com.example.api.songs.entity.PlayList[\"songs\"]->org.hibernate.
这是由于歌曲实体中的playList字段,当尝试获取包含歌曲的播放列表时,我会得到一个递归数组,而不是播放列表的id,这是我想要得到的,实际情况是,我得到了如下内容:
我可以通过在字段中应用JsonIgnore来解决,但是这会影响我,当我去保存播放列表时,我不能将idPlayList字段传递给每首歌,以确保每首歌都保存了相应的idPlayList
我认为最好的办法是在这里建立一个DTO,帮助我建立两个表之间的关系,但是,我不知道如何才能做到这一点,在执行播放列表的get时,只获取idPlayList,在省电时,将idPlayList传递到将与播放列表一起保存的每首歌曲中,或者,如果有另一种方式,我可以存储一个播放列表及其歌曲,并将其直接存储,因为目前我必须由BD为每首歌曲分配idPlayList
>
使用带有LEFT JOIN FETCH
的JPQL查询加载带有歌曲的
PlayList
以获取带有列表的歌曲。所以歌曲
将已经加载,并且歌曲中的playList
将是懒惰的。
select list from PlayList list left join fetch list.songs where list.id = :listId
在Jackson中有
Hibernate5Moules
。它允许省略懒惰的关联。所以杰克逊不会在歌曲中触摸playList
。配置Jackson以省略Spring Boot中的延迟加载属性
建立一个真正的系统。您可以在服务级别上添加
PlayListContent
、Song Content
类并将实体映射到这些类。在这种情况下,您可能不需要Hibernate5Moules。但是最好也尝试一下这个模块。
使用启用数据库登录
application.properties
logging.level.org.springframework.transaction.interceptor=TRACE
logging.level.org.springframework.orm.jpa.JpaTransactionManager=DEBUG
logging.level.org.hibernate.SQL=DEBUG
spring.jpa.properties.hibernate.use_sql_comments=true
仔细检查日志中的事务和SQL。不要让Hibernate产生不必要的查询。
如何用列表保存歌曲
将此方法添加到播放列表中
@Transient
public void addSong(Song song) {
song.setPlayList(this);
songs.add(song);
}
使用
addSong()
方法将歌曲添加到列表中。
保存播放列表
。Hibernate将使用正确的列表id保存列表中的所有歌曲,因为在@OneToMany
中有cascade=CascadeType.All
。
我试图在用户和地址之间建立双向关系, 用户1-------->*地址 但是 地址1-------->1个用户 我在上网时得到了这些信息 > 对于一对一双向关系,拥有方对应于包含对应外键的方 双向关系的反向侧必须通过使用OneToOne、 OneToMany或ManyToMany批注的mappedBy元素来引用其 所属侧。mappedBy元素指定作为 关系所有者的实体中的属性或字段。 但如果我按照情
我很难找到如何在Spring中从@manytomany关系中检索数据。我遇到了无限递归问题,并尝试了一些解决方案,比如使用@JSONIgnoreProperties,但都没有成功。 一个用户可以有多个组,一个组可以有多个用户。我可以将用户添加到组中,但是当涉及到检索与用户关联的所有组时,我会从无限递归中得到堆栈溢出。 理想情况下,我希望能够发送带有用户ID的get请求,然后检索与该用户关联的所有G
问题内容: 假设我有两个实体: 然后,我要保留“客户”实体,然后,参照先前添加的“客户”保留“订单”实体。当我从数据库中检索此客户并调用getOrders时,它将返回空集。这是正常行为吗?如果是,当我添加新的Order实体时,我该怎么做以自动刷新此集合? 问题答案: Jpa不会为您维护关系,因此应用程序需要设置双向关系的两端,以使它们与数据库保持同步。当您设置了order-> customer关系
第404页的“Java持久性2.0,最终发布”有以下示例: 示例3:从一个可嵌入类到另一个实体的一对一关联。 我希望员工内部有多个位置详细信息: 如何更改实体ParkingSpot以指向集合表EMP_LOCATION内的可嵌入Location细节。 应该是 替换为@ElementCollection? 非常感谢。
我正在浏览关于双向关系的Hibernate文档,文档中说: 例7.21。双向一对多,多对一为协会所有者 部队通过部队财产与士兵有双向的一对多关系。您不必(不得)在mappedBy side中定义任何物理映射。 要将双向一对多映射为一对多,并将一对多的一端作为拥有端,您必须删除mappedBy元素,并将多对一@JoinColumn设置为可插入且可更新为false。此解决方案未经优化,将生成其他更新语
问题内容: 我有一个带有和对象的简单模型。 一个问题有很多选择。 许多选择有一个问题 有两种使用Hibernate来实现的方法 实施一:所有者是选择 Question.java Choice.java 实施二:所有者方是质询 Question.java Choice.java 两种实现之间有什么区别? 问题答案: 第一个示例是正常且正确的双向一对多/多对一映射。设置为-attribute(“拥有方