Spring Boot多对多关联时artist_song中间表无数据填充问题
问题分析与解决方案
问题现象
运行Spring Boot应用后,artist表和song表数据正常填充,但多对多关联的中间表artist_song无数据。
核心原因
JPA中多对多关系分为维护端和被维护端:
Artist类是维护端:通过@JoinTable注解定义了中间表结构,负责管理关联关系的持久化。Song类是被维护端:通过mappedBy="songs"声明自己不负责关联关系的维护。
你的代码中,通过Song.addArtist()方法建立关联,虽然双向集合都做了更新,但由于Song是被维护端,JPA不会主动将关联同步到中间表;同时,Artist的songs集合被修改时,Song属于未持久化的临时实体,未触发维护端的关联持久化逻辑,最终导致中间表无数据。
解决方案
方案1:从维护端(Artist)发起关联操作
修改CommandLineRunner中的代码,通过Artist.addSong()方法建立关联,利用维护端特性触发中间表更新:
@Bean @Transactional public CommandLineRunner commandLineRunner() { return args -> { // 创建艺术家 Artist artist1 = new Artist("Sơn Tùng M-TP", "Vietnamese singer-songwriter and actor."); Artist artist2 = new Artist("tlinh", "tlinh is a Vietnamese independent singer and rapper."); Artist artist3 = new Artist("RPT MCK", "RPT MCK is a Vietnamese singer and rapper based in Ha Noi."); // 创建歌曲并从维护端添加关联 Song song1 = new Song("nếu lúc đó", 3794587); artist2.addSong(song1); Song song2 = new Song("Chạy Ngay Đi", 234879825); artist1.addSong(song2); Song song3 = new Song("Hãy Trao Cho Anh", 2387532); artist1.addSong(song3); Song song4 = new Song("Chỉ Một Đêm Nữa Thôi (feat. tlinh)", 782643); artist2.addSong(song4); artist3.addSong(song4); Song song5 = new Song("Em Là Châu Báu", 298374); artist2.addSong(song5); artist3.addSong(song5); // 保存艺术家,由于Artist的cascade=CascadeType.ALL,关联的歌曲会被自动保存 artistRepository.saveAll(List.of(artist1, artist2, artist3)); }; }
方案2:从被维护端操作后,重新保存维护端实体
如果坚持使用Song.addArtist(),需要在建立关联后重新保存Artist(维护端),触发中间表更新:
// 创建歌曲并添加艺术家 Song song1 = new Song("nếu lúc đó", 3794587); song1.addArtist(artist2); songRepository.save(song1); artistRepository.save(artist2); // 重新保存维护端实体 // 其他歌曲同理...
额外优化
去掉Song构造函数中重复初始化artists集合的代码(字段定义时已初始化new HashSet<>()):
public Song(String songName, long songStream) { this.songName = songName; this.songStream = songStream; // 移除 this.artists = new HashSet<>(); }
内容的提问来源于stack exchange,提问作者Tuong Nguyen
相关产品推荐
相关产品推荐

