Spring 引导中的@ManyToMany(无法延迟初始化 collection 角色:com.example.demo.Movie.actors,无法初始化代理 - 否 Session)

@ManyToMany in Spring Boot (failed to lazily initialize a collection of role: com.example.demo.Movie.actors, could not initialize proxy - no Session)

我目前正在尝试 Spring 启动并使用一个测试项目,我 运行 遇到了 @ManyToMany-Relationships 的问题。

应该有可以保存的电影,它们可以有多种类型、演员等等。演员可以参演很多电影

现在我可以将电影保存到数据库中,但由于某些原因我只能读取简单的数据,例如标题或制作年份。如果我尝试将流派打印到命令行或参与的演员,我会收到以下异常:

Exception in thread "main" org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.example.demo.Movie.actors, could not initialize proxy - no Session at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:612) at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:218) at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:591) at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149) at org.hibernate.collection.internal.PersistentBag.get(PersistentBag.java:561) at com.example.demo.MoviedbApplication.main(MoviedbApplication.java:75)

这是我的代码:

        ConfigurableApplicationContext run = SpringApplication.run(MoviedbApplication.class, args); 
        GenreRepository genreRepository = run.getBean(GenreRepository.class);
    ActorRepository actorRepository = run.getBean(ActorRepository.class);
    AuthorRepository authorRepository = run.getBean(AuthorRepository.class);
    DirectorRepository directorRepository = run.getBean(DirectorRepository.class);
    MovieRepository movieRepository = run.getBean(MovieRepository.class);

    Movie theGodfather = new Movie();
    theGodfather.setTitle("Der Pate");
    theGodfather.setYear(1972);
    theGodfather.setOriginalTitle("The Godfather");
    theGodfather.setLengthInMinutes(175);
    theGodfather.setPlot("Der alternde Patriarch einer Verbrecherdynastie will die Herrschaft über sein geheimes Reich auf seinen widerwilligen Sohn übertragen.");
    theGodfather.setAge(16);

    List<Director> dirs = new ArrayList<>();
    dirs.add(new Director("Francis Ford Coppola"));

    List<Actor> acts = new ArrayList<>();
    acts.add(new Actor("Marlon Brando"));
    acts.add(new Actor("Al Pacino"));
    acts.add(new Actor("James Caan"));

    List<Genre> genres = new ArrayList<>();
    genres.add(new Genre("Krimi"));
    genres.add(new Genre("Drama"));

    List<Author> authors = new ArrayList<>();
    authors.add(new Author("Mario Puzo"));
    authors.add(new Author("Francis Ford Coppola"));

    theGodfather.setActors(acts);
    theGodfather.setAuthors(authors);
    theGodfather.setDirectors(dirs);
    theGodfather.setGenres(genres);
    
    
    movieRepository.save(theGodfather);

    List<Movie> der_pate = movieRepository.findByTitle("Der Pate");

    Movie movie = der_pate.get(0);


    System.out.println("Test");
    System.out.println(movie.getYear());
    System.out.println(movie.getTitle());
    System.out.println(movie.getId());
    System.out.println(movie.getActors().get(0).getName());
    System.out.println(movie.getAuthors().get(0).getName());


@Entity
@Table(name="movies")
public class Movie {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    private String title;
    private String originalTitle;
    private int year;
    private int age;
    private int lengthInMinutes;
    private String plot;
    private String linkToCover;

    @ManyToMany
    @Cascade({CascadeType.PERSIST})
    @JoinTable(
            name = "movie_genres",
            joinColumns = @JoinColumn(name = "movie_id"),
            inverseJoinColumns = @JoinColumn(name = "genre_id")
    )
    private List<Genre> genres = new ArrayList<>();

    @ManyToMany
    @Cascade({CascadeType.PERSIST})
    @JoinTable(
            name = "movie_actors",
            joinColumns = @JoinColumn(name = "movie_id"),
            inverseJoinColumns = @JoinColumn(name="actor_id")
    )
    private List<Actor> actors = new ArrayList<>();

    @ManyToMany
    @Cascade({CascadeType.PERSIST})
    @JoinTable(
            name = "movie_directors",
            joinColumns = @JoinColumn(name = "movie_id"),
            inverseJoinColumns = @JoinColumn(name = "director_id")
    )
    private List<Director> directors = new ArrayList<>();

    @ManyToMany
    @Cascade({CascadeType.PERSIST})
    @JoinTable(
            name = "movie_authors",
            joinColumns = @JoinColumn(name = "movie_id"),
            inverseJoinColumns = @JoinColumn(name = "author_id")
    )
    private List<Author> authors = new ArrayList<>();


@ManyToMany
@Cascade({CascadeType.PERSIST})
@JoinTable(
        name = "movie_genres",
        joinColumns = @JoinColumn(name = "movie_id"),
        inverseJoinColumns = @JoinColumn(name = "genre_id")
)
private List<Genre> genres = new ArrayList<>();

@ManyToMany
@Cascade({CascadeType.PERSIST})
@JoinTable(
        name = "movie_actors",
        joinColumns = @JoinColumn(name = "movie_id"),
        inverseJoinColumns = @JoinColumn(name="actor_id")
)
private List<Actor> actors = new ArrayList<>();

@ManyToMany
@Cascade({CascadeType.PERSIST})
@JoinTable(
        name = "movie_directors",
        joinColumns = @JoinColumn(name = "movie_id"),
        inverseJoinColumns = @JoinColumn(name = "director_id")
)
private List<Director> directors = new ArrayList<>();

@ManyToMany
@Cascade({CascadeType.PERSIST})
@JoinTable(
        name = "movie_authors",
        joinColumns = @JoinColumn(name = "movie_id"),
        inverseJoinColumns = @JoinColumn(name = "author_id")
)
private List<Author> authors = new ArrayList<>();

@Entity @Table(name="Actor") public class Actor {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;

@ManyToMany
@Cascade({CascadeType.PERSIST})
@JoinColumn(name = "movie_id")
private List<Movie> movies = new ArrayList<>();

public Actor(String name) {
    this.name=name;
}`

我已经尝试过将演员和流派保存到相应的存储库中,这会导致以下异常:

detached entity passed to persist: com.example.demo.Actor; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: com.example.demo.Actor

我也摸索过 eager fetching 之类的东西..现在我想,我在这里遗漏了一些非常重要的东西,所以很抱歉,如果这听起来像是一个初学者问题..

非常感谢您!

关于抓取类型和会话管理。如果你想访问与你的电影相关的演员,你需要在这种情况下将你的获取类型设置为 @ManyToMany(fetch = FetchType.EAGER)。 对于 ManyToMany 关系,默认的获取类型是 LAZY。 可能是您的电影实体在从数据库中获取后与会话分离。所以,即使你有一行 movie.getActors() 你也会得到 LazyInitializationException。 有关 hibernate 延迟加载的详细信息,请参见。 https://howtodoinjava.com/hibernate/lazy-loading-in-hibernate/

在您的“findByTitle”方法中,您必须加载 ManyToMany 关系,因为默认情况下它们是 LAZY 获取的。要加载集合,您可以使用 size() 方法。例如:

List<Movie> findByTitle(String title) {
   List<Movie> movies;
   //fetch movies

   //now load ManyToMany relationships
   for(var movie : movies) {
     movie.getActors().size();
     movie.getAuthors().size();
   }
   return movies;
}

我还建议在多对多关系中使用集合而不是列表