我正在使用Hibernate / JPA完成我的第一个Spring启动应用程序。我创建了两个@Entities
@ManyToMany
映射:Team
和Game
。
目前,数据库有一个包含teams
的表格,我想插入引用两个game
的{{1}}。
问题是我收到错误:
teams
我做错了什么?
`org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataLoader': Invocation of init method failed; nested exception is org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.example.data.entities.FootballTeam.homeGames, could not initialize proxy - no Session
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:136) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:408) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:838) ~[spring-context-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:537) ~[spring-context-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118) ~[spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752) [spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]
at org.springframework.boot.SpringApplication.doRun(SpringApplication.java:347) [spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:295) [spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1112) [spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1101) [spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE]
at com.example.FootballPoolSpringSpringBoot.main(FootballPoolSpringSpringBoot.java:11) [classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_65]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_65]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_65]
at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_65]
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-1.3.0.RELEASE.jar:1.3.0.RELEASE]
Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.example.data.entities.FootballTeam.homeGames, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:576) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:215) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:555) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.write(AbstractPersistentCollection.java:400) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
at org.hibernate.collection.internal.PersistentBag.add(PersistentBag.java:314) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
at com.example.service.DataLoader.loadData(DataLoader.java:106) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_65]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_65]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_65]
at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_65]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:354) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:305) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:133) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]
... 23 common frames omitted`.
Game.java
@Entity
public class FootballTeam {
private FootballTeam(){/**/}
public FootballTeam(String teamName) {
this.teamName = teamName;
}
@Id
@GeneratedValue
private Long teamId;
@Column(name = "team_name", unique = true)
private String teamName;
@Column(name = "short_name", unique = true)
private String teamShortName;
private String teamLeague;
private String teamDivision;
@Embedded
private Location teamLocation;
@ManyToMany(cascade = CascadeType.ALL, mappedBy = "favoriteTeams")
private List<Users> fans = new ArrayList<>();
@OneToMany(mappedBy = "homeTeam")
List<FootballGame> homeGames = new ArrayList<>();
@OneToMany(mappedBy = "visitingTeam")
List<FootballGame> awayGames = new ArrayList<>();
/* getters and setters omitted for brevity */
}
DataLoader.class
@Entity
@Table(name = "football_game",
uniqueConstraints= @UniqueConstraint(
columnNames={"played_on", "home_team", "visiting_team"}))
public class FootballGame {
private FootballGame(){/**/}
public FootballGame(Date playedOn, FootballTeam homeTeam, FootballTeam visitingTeam) {
this.homeTeam = homeTeam;
this.playedOn = playedOn;
this.visitingTeam = visitingTeam;
}
@Id
@GeneratedValue
private Long gameId;
@Column(name = "played_on", nullable = false)
private Date playedOn;
@ManyToOne(cascade = CascadeType.MERGE)
@JoinColumn(name = "home_team", nullable = false)
private FootballTeam homeTeam;
@ManyToOne(cascade = CascadeType.MERGE)
@JoinColumn(name = "visiting_team", nullable = false)
private FootballTeam visitingTeam;
private int homeTeamScore;
private int visitingTeamScore;
@OneToOne(mappedBy = "footballGame")
private FootballPool footballPool;
/* getters and setters omitted for brevity */
}
答案 0 :(得分:2)
这指向您的错误:
Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.example.data.entities.FootballTeam.homeGames, could not initialize proxy - no Session
@OneToMany
和@ManyToMany
(以及Hibernate,我相信@ManyToOne
&amp; @OneToOne
)会被懒惰地实例化。这意味着它不会在需要之前将对象或对象列表从数据库加载到内存中。在您的情况下,您将获得异常,因为当您引用FootballTeam
类时,会话已关闭或未在范围内。
如果映射不是很大,您可以在映射上指定提取策略:
@OneToMany(mappedBy = "homeTeam", fetch = FetchType.EAGER)
这会立即将实例加载到内存中。请注意,您可能需要使用所有映射。
UDPATE:以下选项不适用于@PostContruct
方法。请参阅下面的DavidLizárraga评论。适用于更常见的情况,例如拨打Controller
至Service
班级,并使用Service
@Transactional
方法
如果不能立即将所有内容全部加载到内存中,则在引用映射对象时,必须确保Session
仍在范围内。对于您当前的情况,可以通过使用@Transactional
注释注释您的方法来完成此操作。通常,您需要确保访问延迟加载的对象的方法是在@Transaction
方法中完成的。
答案 1 :(得分:1)
在JPA多对多关系中,如果cascade类型已设置为CascadeType.PERSIST(或CascadeType.ALL,其中包括CascadeType.PERSIST),则在保存父级并使用子级引用更新它时,它将试着再次拯救孩子。
由于您正在使用Hibernate,请尝试:
@ManyToOne(cascade = CascadeType.MERGE)
答案 2 :(得分:1)
因此,如果您收到“分离实体错误”,这意味着 您的子对象没有要跟踪的任何标志。因此,只要你保存它,就会将child视为新对象。因此,只需将带有注释@version和版本字段的实体上的“version”字段放到相关表中。 另外,在保存新孩子时,请确保在孩子身上设置父母。