java - 在同一事务中查找实体时,多对一关系始终为空
问题描述
我有一个与 ModeratorEntity 具有多对一关系的 ConversationEntity
@Entity
@Table(name="CONVERSATIONS")
public class ConversationEntity {
@Id
private Integer id;
private Integer moderatorId;
@ManyToOne
@JoinColumn(name="moderatorId", insertable=false, updatable=false)
private ModeratorEntity moderator;
}
@Entity
@Table(name="MODERATORS")
public class ModeratorEntity {
@Id
private Integer id;
private Integer name;
}
以及一个具有事务方法的服务类,它首先保存 ModeratorEntity,然后保存之前创建的具有 moderatorId 的 ConversationEntity
@Transactional
public void doStuff(Moderator moderator, Integer conversationId) {
Integer moderatorId = moderatorService.save(moderator);
Integer conversationId = conversationService.save(conversationId, moderatorId);
//do other stuff
Conversation conversation = conversationService.findById(conversationId);
}
当我试图在同一事务中通过 id 查找 ConversationEntity 时,下面几行,我得到了设置了字段 moderatorId 但 ModeratorEntity 对象 = null 的 ConversationEntity。
如果我在事务之外执行此操作,我将正确设置 ModeratorEntity 对象。
我尝试在 ModeratorRepository 和 ConversationRepository 中使用 saveAndFlush 并在 ManyToOne 关系中设置 FetchType.EAGER 但它们都不起作用
解决方案
有很多关于类似问题的问题。例如,与 Spring Data 双向关系的 @Transactional 返回 null和Hibernate:比较当前和上一个记录。
只要您在单个事务中,您将始终获得相同的实例,并且实际上不会从数据库中加载任何数据。而且因为(至少看起来)您从未将引用设置为ModeratorEntity
it stays null
。
一旦你在一个新事务中,数据库就会被访问,JPA 会填充一个新实例,现在包括一个ModeratorEntity
引用。
因此,可能的修复是:
代替 id 让我们
moderatorService.save
返回一个实体并将其设置在Conversation
. 你还不如放弃moderatorId
. 这是使用 JPA 做事的惯用方式。在单独的事务中执行查询。弹簧
TransactionTemplate
可能会派上用场。虽然这确实有效,但它会导致 JPA 内部渗透到您的应用程序中,我建议避免这种情况。