@Transactional 与 Spring Data 的双向关系返回 null
Posted
技术标签:
【中文标题】@Transactional 与 Spring Data 的双向关系返回 null【英文标题】:@Transactional in bidirectional relation with Spring Data returns null 【发布时间】:2019-04-06 05:47:21 【问题描述】:我正在使用 Spring Data 和 @Transactional 注释(用于测试后的自动回滚)。 我在帐户和用户(拥有方)之间有简单的双向关系:
@Entity
@Table(name = "ACCOUNT_T")
public class AccountEntity
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String email;
private String password;
private String verificationCode;
private Boolean active = false;
@OneToOne(mappedBy = "account", fetch = FetchType.EAGER,
cascade = CascadeType.MERGE, CascadeType.PERSIST,
CascadeType.DETACH, CascadeType.REFRESH)
private UserEntity user;
@Entity
@Table(name = "USER_T")
public class UserEntity
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String surname;
private String phone;
private LocalDate birthDate;
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
@JoinColumn(name = "account_id")
private AccountEntity account;
我正在使用 JpaRepositories 并且获取设置为渴望。 为什么有时当我从数据库中获取对象时,我无法获取他们的孩子 返回对象-null。这取决于我从哪一侧添加对象。 我使用 Junit5 编写了简单的测试:
@ExtendWith(SpringExtension.class)
@SpringBootTest
@Transactional
class UserAndAccountRepositoriesTest
void testA()
UserEntity userEntity = new UserEntity();
setUserProperties(userEntity);
AccountEntity accountEntity = new AccountEntity();
setAccountProperties(accountEntity); //just setting values for fields
accountEntity.setUser(userEntity);
accountRepository.save(accountEntity);
accountRepository.findAll().get(0).getUser(); //returns user
userRepository.findAll().get(0).getAccount(); //returns null,but should return account related to that user
void testB()
UserEntity userEntity = new UserEntity();
setUserProperties(userEntity);
AccountEntity accountEntity = new AccountEntity();
setAccountProperties(accountEntity);
accountEntity.setUser(userEntity);
accountRepository.save(accountEntity);
accountRepository.findAll().get(0).getUser(); //again returns null,but shouldn't
userRepository.findAll().get(0).getAccount(); //returns account
没有@Transactional
一切正常 - 我不会为空。
我做错了什么?
【问题讨论】:
你能在保存之前尝试设置userEntity.setAccount(accountEntity)
吗?
那行得通 :) 但是为什么呢?没有@Transactional,我不必从两边添加
通常你需要为任何类型的关系设置双方。 Hibernate 需要这种级别的明确性
为什么..因为它们相互关联并且默认情况下不连接,除非您为它们设置默认值,因此为空。如果您明确设置它们,正如@buræquete 所指出的那样,它们就是。
我明白,但没有@Transactional 我只能从一侧设置并且它可以工作。我知道我很好奇:)
【参考方案1】:
您需要设置关系的双方以明确定义它。
尝试在您的设置案例中添加userEntity.setAccount(accountEntity)
,这将解决问题。
Hibernate 不会帮助您并假设仅仅因为您设置了 a -> b
,它就会在其他实体中为您设置 b <- a
。
它在没有@Transactional
的情况下可能工作的原因是,如果没有注释,您将设置数据提交到您正在使用的任何数据源中,并且最后没有回滚,因为您选择的数据没有任何@987654325 @ 与findAll
,您将获得先前已提交的用户/帐户实体,有些有关系,有些没有,因此您得到随机错误。
【讨论】:
【参考方案2】:这是因为您没有在userEntity
中设置帐户。请尝试如下:
userEntity.setAccount(accountEntity);
【讨论】:
【参考方案3】:我将根据您是否在交易中解释为什么行为会有所不同:
当您进行交易时:
a) 任何获取您在此事务之前创建的实体 A 的任何获取(因此它已经在数据库中)将在内存地址方面返回一个 新对象,并且休眠将解析其双向关系,即使您没有明确设置。
b) 任何获取您在此事务中较早创建的实体 B 的任何获取(因此尚未在 DB 中)将在内存地址方面返回 相同的对象,所以它确实是同一个对象,因此如果你没有明确设置它的双向关系,它不会存在,直到你设置它或直到事务结束(因为它会有效地将 B 保存在 DB 中)并且你再次获取 B。
当您不参与交易时:
获取任何实体的任何获取都将像情况 a) 中描述的那样。
结论:
作者是b)。
【讨论】:
以上是关于@Transactional 与 Spring Data 的双向关系返回 null的主要内容,如果未能解决你的问题,请参考以下文章
Spring @transactional 是不是与 MongoDB 一起使用?
如何将 @Transactional 与 Spring Data 一起使用?
@Transactional 与 Spring Data 的双向关系返回 null