我目前正在学习Hibernate,但我一直坚持从hibernate(spring-jpa)中的多对多关系中获取数据。我正在尝试通过ID获取数据,但它根本无法正常工作。
我知道这是不现实的,但是可以从很多人那里取一本书。
问题是,在哪个类中放入EAGER访存类型无关紧要,在第二类中将LAZY访存类型放进去,这是无关紧要的:
LazyInitializationException:无法延迟初始化角色集合
但是,如果我在两个类中都使用EAGER提取类型,则会抛出StackOverFlowError
。
多对多逻辑是这样的,我们在图书馆有一本书,我们有很多人可以拿很多书,而很多人可以拿本书。
我试图将EAGER的获取都放在这两个类中,但这给了我StackOverFlowError
。
我不得不提到我正在使用JpaRepository
界面。
Person类:
@Entity
@Table(name = "persons")
public class Person { // (in library)
@Id
@Column(name = "id")
@GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
@Column(name = "name")
private String name;
@Column(name = "number_card")
private int numberCard;
@Column(name = "time_of_account_creating")
@Temporal(TemporalType.DATE)
private Date date;
@ManyToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
List<Book> books = new ArrayList<>();
public Person() {
this.date = new Date();
}
public Person(String name, int numberCard) {
this.name = name;
this.numberCard = numberCard;
this.date = new Date();
}
public void addBook(Book book) {
this.books.add(book);
}
// gettters and setters
Book类:
@Entity
@Table(name = "books")
public class Book { // (in library)
@Id
@Column(name = "id")
@GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
@Column(name = "release_year")
private int releaseYear;
@Column(name = "name")
private String name;
@ManyToMany(mappedBy = "books", cascade=CascadeType.ALL, fetch = FetchType.LAZY)
private List<Person> persons = new ArrayList<>();
public Book() {
}
public Book(int releaseYear, String name) {
this.releaseYear = releaseYear;
this.name = name;
}
public List<Person> getPersons() {
return persons;
}
public void addPerson(Person person) {
this.persons.add(person);
}
// getters and setters
@SpringBootApplication中的主要方法:
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(HibernateDemoApplication.class, args);
PersonRepository personRepository = context.getBean(PersonRepository.class);
System.out.println(personRepository.findById(4));
}
application.property:
spring.datasource.url = jdbc:mysql://localhost:3306/${DB}
spring.datasource.username = ${username}
spring.datasource.password = ${password}
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto = update
spring.jpa.show-sql=true
输出控制台:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.5.RELEASE)
2020-03-26 15:59:27.228 INFO 18912 --- [ main] c.e.h.HibernateDemoApplication : Starting HibernateDemoApplication on abu with PID 18912 (/home/yoav/hibernateDemo/target/classes started by yoav in /home/yoav/hibernateDemo)
2020-03-26 15:59:27.232 INFO 18912 --- [ main] c.e.h.HibernateDemoApplication : No active profile set, falling back to default profiles: default
2020-03-26 15:59:28.450 INFO 18912 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2020-03-26 15:59:28.625 INFO 18912 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 131ms. Found 6 JPA repository interfaces.
2020-03-26 15:59:31.886 INFO 18912 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2020-03-26 15:59:31.928 INFO 18912 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2020-03-26 15:59:31.929 INFO 18912 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.31]
2020-03-26 15:59:32.101 INFO 18912 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2020-03-26 15:59:32.101 INFO 18912 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 4687 ms
2020-03-26 15:59:32.636 INFO 18912 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default]
2020-03-26 15:59:33.001 INFO 18912 --- [ main] org.hibernate.Version : HHH000412: Hibernate ORM core version 5.4.12.Final
2020-03-26 15:59:33.631 INFO 18912 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.1.0.Final}
2020-03-26 15:59:35.055 INFO 18912 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2020-03-26 15:59:37.374 INFO 18912 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2020-03-26 15:59:37.689 INFO 18912 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQL5InnoDBDialect
Hibernate: alter table students add constraint FKrpifpqwvgu2pg2lib5c787vs foreign key (laptop_id) references laptops (id)
2020-03-26 15:59:41.092 INFO 18912 --- [ main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2020-03-26 15:59:41.105 INFO 18912 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2020-03-26 15:59:42.982 WARN 18912 --- [ main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2020-03-26 15:59:43.406 INFO 18912 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-03-26 15:59:44.775 INFO 18912 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2020-03-26 15:59:45.009 INFO 18912 --- [ main] c.e.h.HibernateDemoApplication : Started HibernateDemoApplication in 18.339 seconds (JVM running for 18.756)
Hibernate: select person0_.id as id1_5_0_, person0_.time_of_account_creating as time_of_2_5_0_, person0_.name as name3_5_0_, person0_.number_card as number_c4_5_0_, books1_.persons_id as persons_1_6_1_, book2_.id as books_id2_6_1_, book2_.id as id1_0_2_, book2_.name as name2_0_2_, book2_.release_year as release_3_0_2_ from persons person0_ left outer join persons_books books1_ on person0_.id=books1_.persons_id left outer join books book2_ on books1_.books_id=book2_.id where person0_.id=?
Exception in thread "main" org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.example.hibernateDemo.models.Book.persons, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:606)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:218)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149)
at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:621)
at java.lang.String.valueOf(String.java:2994)
我不得不再说一遍,如果我在两个类中都添加了EAGER提取类型,则会得到StackOverFlowError
。
答案 0 :(得分:0)
我知道这个线程已经使用了几个月,但是将来会问:
问题:
您隐藏Person#toString方法。在方法中,您可以访问书籍字段。很好,因为fetchtype为EAGER。问题是您访问Book#toString,并在其中访问人员字段。此字段为LAZY。由于您将不会在事务内访问此字段,因此始终会获得LazyInitializationException。
解决方案: