我有一个简单的@OneToMany关系的两个对象,如下所示:
父:
@Entity
public class ParentAccount {
@Id
@GeneratedValue
private long id;
private String name;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "parentAccount")
private Set<LinkedAccount> linkedAccounts;
}
子:
@Entity
public class LinkedAccount {
@Id
@GeneratedValue
private long id;
@ManyToOne(optional = false)
private ParentAccount parentAccount;
private String name;
// empty constructor for JPA
public LinkedAccount() {
}
}
我使用Spring CrudRepository
来操作这些实体。但是,当调用ParentAccount parent = parentAccountRepository.findOne(id);
时,某种无限循环开始发生,并且hibernate在整个控制台上发送垃圾邮件:
Hibernate: select linkedacco0_.parent_account_id as parent_a6_1_0_, linkedacco0_.id as id1_0_0_, linkedacco0_.id as id1_0_1_, linkedacco0_.aws_id as aws_id2_0_1_, linkedacco0_.key_id as key_id3_0_1_, linkedacco0_.name as name4_0_1_, linkedacco0_.parent_account_id as parent_a6_0_1_, linkedacco0_.secret_key as secret_k5_0_1_ from linked_account linkedacco0_ where linkedacco0_.parent_account_id=?
我尝试将获取类型更改为LAZY,但后来我收到此错误:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.berrycloud.scheduler.model.ParentAccount.linkedAccounts, could not initialize proxy - no Session
(似乎它试图在事务上下文之外进行延迟加载)。
这是我的CRUD存储库:
@Repository
public interface ParentAccountRepository extends CrudRepository<ParentAccount, Long> {
}
有人能告诉我如何解决这个问题吗?我更喜欢EAGER fetch的解决方案。感谢您提供任何提示
编辑:这是我正在使用的架构
CREATE TABLE parent_account (
id BIGINT auto_increment,
name VARCHAR(80) null,
PRIMARY KEY (`id`)
);
CREATE TABLE linked_account (
id BIGINT auto_increment,
parent_account_id BIGINT,
name VARCHAR(80) null,
FOREIGN KEY (`parent_account_id`) REFERENCES `parent_account` (`id`),
PRIMARY KEY (`id`)
);
答案 0 :(得分:14)
第一个答案表明:
不要在
@Data
类上使用Lombok的@Entity
注释。
原因: @Data
生成使用生成的getter的hashcode()
,equals()
和toString()
方法。使用getter意味着即使属性标记为 FetchType = LAZY ,也会获取新数据。
在某个地方,hibernate尝试使用toString()
记录数据,然后崩溃。
答案 1 :(得分:6)
问题解决了。我在LinkedAccount中使用了一个自定义@toString
方法,该方法引用了ParentAccount。我不知道这可能会导致任何问题,因此我没有在我的问题中包含toString。
显然,这导致延迟加载的无限循环并删除此引用修复了问题。
答案 2 :(得分:0)
这样的东西不起作用?
@Entity
public class Account {
@Id
@GeneratedValue
private long id;
private String name;
@ManyToOne(cascade={CascadeType.ALL})
@JoinColumn(name="manager_id")
private Account manager;
@OneToMany((fetch = FetchType.EAGER, mappedBy="manager")
private Set<Account> linkedAccounts = new HashSet<Account>();
}
答案 3 :(得分:0)
由于定义不正确的Jackson2HttpMessageConverter,我最近遇到了这个问题。
我做了类似以下的事情。
@Bean
RestTemplate restTemplate(@Qualifier("halJacksonHttpMessageConverter")
TypeConstrainedMappingJackson2HttpMessageConverter halConverter) {
final RestTemplate template = new RestTemplateBuilder().build();
halConverter.setSupportedMediaTypes(List.of(/* some media types */));
final List<HttpMessageConverter<?>> converters = template.getMessageConverters();
converters.add(halConverter);
template.setMessageConverters(converters);
return template;
}
这引起了一个问题,因为媒体类型未包括所有默认值。将其更改为以下内容可以解决我的问题。
halConverter.setSupportedMediaTypes(
new ImmutableList.Builder<MediaType>()
.addAll(halConverter.getSupportedMediaTypes())
.add(/* my custom media type */)
.build()
);
答案 4 :(得分:0)
正如user1819111所说,龙目岛的@Data
与@Entity
和FetchType=LAZY
不兼容。我曾经使用过Lombok.Data
(@Data
),但遇到了这个错误。
由于我不想创建所有的get / set,因此只需将 Lombok @Setter
和@Getter
放在您的班级中,一切就可以正常进行。
@Setter
@Getter
@Entity
@Table(name = "file")
@SequenceGenerator(name = "File_Sequence", allocationSize=1, sequenceName = "file_id_seq")
public class MyClass{
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "File_Sequence")
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
@OneToMany(mappedBy = "file", cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
private Set<Base2FileDetail> details = new HashSet<>();
}