所以我正在围绕我创建的某些Spring JpaRepository编写一些逻辑测试。我正在使用嵌入式内存H2数据库来执行此操作。我看到一个奇怪的场景,其中我的OneToOne映射实体行为不正常。
我的User
和SSOUser
是具有OneToOne关系的实体,其中SSOUser
实体仅具有使用我们的SSO解决方案登录的用户的其他元数据。在下面提供的测试代码中,当未应用@Transactional
时,一切正常。但是,当我添加@Transactional
时,它在注释行上失败:
@Test
public void test_saveFindUserAndSsoUser() throws Exception {
User user = mockUser();
user = userCarrierRepository.saveAndFlush(user);
SSOUser ssoUser = new SSOUser();
ssoUser.setUser(user);
ssoUser = ssoUserRepository.saveAndFlush(ssoUser);
assertNotNull(user.getId());
assertNotNull(ssoUser.getId());
SSOUser ssoUser2 = ssoUserRepository.findById(ssoUser.getId())
.orElseThrow(() -> new Exception("Could not find SSO User by ID"));
assertThat(ssoUser2, allOf(
hasProperty("id", equalTo(ssoUser.getId())),
hasProperty("user", notNullValue())
));
assertThat(ssoUser2.getUser(), hasProperty("id", equalTo(user.getId())));
final User user2 = userCarrierRepository.findById(user.getId())
.orElseThrow(() -> new Exception("Could not find User by ID"));
assertThat(user2, allOf(
hasProperty("id", equalTo(user.getId())),
hasProperty("ssoUser", notNullValue()) // FAILS HERE BECAUSE ssoUser IS NULL
));
assertThat(user2.getSsoUser(), hasProperty("id", equalTo(ssoUser.getId())));
}
使用Lombok的用户实体为:
@Data
@Entity
@Table(name="user")
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="id")
private Long id;
@OneToOne(fetch = FetchType.LAZY, mappedBy = "user")
private SSOUser ssoUser;
public boolean isSSOUser() {
return ssoUser != null;
}
}
使用Lombok的SSOUser实体为:
@Data
@Entity
@Table(name = "sso_user")
public class SSOUser implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
}
下面是将适当的表添加到我们的数据库中的SQL DDL语句:
CREATE TABLE sso_user (
id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES public.user (id)
);
因此,回到原始代码,User
实体将ssoUser
字段保存为空。但是,SSOUser
实体正在与有效的User
实体一起保存。我希望sso_user
表在user_id
列中包含适当的值。
由于sso_user
表中的数据正确,因此我希望userCarrierRepository.findById(...)
返回一个User
,其中包括连接的ssoUser
,就像我会期望sslUserRepository.findById(...)
返回SSOUser
,其中包括加入的user
。
但是,事实并非如此。与联接的实体一起返回的只是SSOUser,而没有返回该用户。
同样,仅当我在此处提供的代码中添加@Transactional时,才会发生这种情况。没有该注释,一切都会按我的预期进行。
我希望有人可以帮我解释一下。非常感谢。