Spring JPA OneToOne映射的实体在事务测试中无法正常运行

时间:2019-03-18 20:25:04

标签: java spring jpa junit

所以我正在围绕我创建的某些Spring JpaRepository编写一些逻辑测试。我正在使用嵌入式内存H2数据库来执行此操作。我看到一个奇怪的场景,其中我的OneToOne映射实体行为不正常。

我的UserSSOUser是具有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时,才会发生这种情况。没有该注释,一切都会按我的预期进行。

我希望有人可以帮我解释一下。非常感谢。

0 个答案:

没有答案