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;
}
我还建议在多对多关系中使用集合而不是列表
我目前正在尝试 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;
}
我还建议在多对多关系中使用集合而不是列表