繁体   English   中英

Hibernatre(jpa 存储库)- 尝试获取多对多关系数据

[英]Hibernatre (jpa repository) - trying to fetch many-to-many relationship data

我目前正在学习 Hibernate,我一直在从 Hibernate (spring-jpa) 中的多对多关系中获取数据。 我正在尝试通过 id 获取数据,但它不起作用。

我知道这不现实,但一本书可以从很多人那里拿走。

问题是,我在哪个类中放置 fetch 类型 EAGER 并在第二个我放置 LAZY fetch 类型并不重要,它会抛出:

LazyInitializationException:未能延迟初始化角色集合

但是,如果我将 EAGER fetch 类型放在两个类中,则会StackOverFlowError

多对多的逻辑是这样的,我们在图书馆里有一本书,我们有很多人,很多人可以拿很多书,书可以从很多人那里拿走。

我试图将 EAGER fetching 放在两个类中,但它给了我StackOverFlowError

我不得不提到我正在使用JpaRepository接口。

人物类:

@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

书类:

@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 fetch 类型,我会收到StackOverFlowError

我知道这个线程已经有几个月的历史了,但是对于将来的提问者:

问题:

您隐藏了 Person#toString 方法。 在您访问书籍字段的方法中。 这很好,因为 fetchtype 是 EAGER。 问题是您访问 Book#toString 时访问人员字段。 这个字段是懒惰的。 由于您不会在事务中访问此字段,因此您将始终收到 LazyInitializationException。

解决方案:

  1. 开启交易。 (谷歌 jpa 交易)
  2. 加载实体。
  3. 访问惰性字段。 它会起作用!
  4. 关闭事务:注意,事务中加载实体的所有更改都会自动保存到数据库中,无需手动通过存储库DAO保存!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM