CRUD存储库不遵守UNIQUE约束

时间:2019-05-11 15:52:17

标签: hibernate spring-boot kotlin spring-data-jpa h2

我有以下JPA实体

@Entity
class UserEntity {

    companion object {
        fun fromParameters(uuid: String, email: String, password: String, firstName: String, lastName: String) =
            UserEntity().apply {
                this.uuid = uuid
                this.email = email
                this.password = password
                this.firstName = firstName
                this.lastName = lastName
            }
    }

    @Id
    lateinit var uuid: String

    @Column(nullable = false, unique = true)
    lateinit var email: String

    @Column(nullable = false)
    lateinit var password: String

    @Column(nullable = false)
    lateinit var firstName: String

    @Column(nullable = false)
    lateinit var lastName: String
}

这是我的测试,用于检查UNIQUE约束,并使用相同的电子邮件插入另一个用户。

@RunWith(SpringRunner::class)
@DataJpaTest
@AutoConfigureTestEntityManager
class TestUserCrudRepository {

    @Autowired
    private lateinit var userCrudRepository: UserCrudRepository

    private val testUserEntity = UserEntity.fromParameters(
        UUID.randomUUID().toString(),
        "test@test.com",
        "password".toHash(),
        "Caetano",
        "Veloso"
    )

    @Test
    fun `when email already exists it should throw error`() {
        with (userCrudRepository) {
            save(testUserEntity)
            val newUserEntity = with (testUserEntity) { UserEntity.fromParameters(UUID.randomUUID().toString(), email, password, firstName, lastName) }
            shouldThrow<SQLException> { save(newUserEntity) }
        }
    }
}

新实体总是插入重复的电子邮件,不会引发任何异常。

Expected exception java.sql.SQLException but no exception was thrown

我在日志中看到该表已根据给定的约束正确创建。

Hibernate: drop table user_entity if exists
Hibernate: create table user_entity (uuid varchar(255) not null, email varchar(255) not null, first_name varchar(255) not null, last_name varchar(255) not null, password varchar(255) not null, primary key (uuid))
Hibernate: alter table user_entity add constraint UK_4xad1enskw4j1t2866f7sodrx unique (email)

谢谢!

1 个答案:

答案 0 :(得分:2)

发生这种情况是因为没有发布$parts = explode("]", $content); $i=0; while (isset($solution[$i])){ //answer correct if($solution[$i] == $input[$i]){ //replace placeholder > green solution $parts[$i] = str_replace("[".$solution[$i], "[".$solution_green[$i], $parts[$i]); } //answer wrong else{ //replace placeholder > input box to try again $parts[$i] = str_replace("[".$solution[$i], "[".$solution_box[$i], $parts[$i]); } $i++; } $content = implode( "]", $parts); 语句。

Hibernate不会insert会话,除非有充分的理由这样做

  1. @DataJpaTest@Transactional。这意味着在其中执行的flush方法返回的事务将在该方法返回后回滚。
  2. @Test映射还鼓励休眠模式延迟UserEntity(尝试在insert属性上使用@GeneratedValue(strategy = IDENTITY)来强制发出id s)

不深入细节,运行测试时会发生以下情况:

  1. Spring的测试基础架构insert的交易
  2. begin方法运行
  3. @Test-Hibernate意识到没有理由访问数据库并延迟 save(testUserEntity)
  4. insert-与以前的
  5. shouldThrow<SQLException> { save(newUserEntity) }方法返回
  6. 事务回滚。 Hibernate确实执行@Test,因为没有理由。

如何解决?

最简单的方法是使用JpaRepository#flush

insert

请注意,CrudRepository中没有with (userCrudRepository) { save(testUserEntity) val newUserEntity = with (testUserEntity) { UserEntity.fromParameters(UUID.randomUUID().toString(), email, password, firstName, lastName) } save(newUserEntity) assertThrows<DataIntegrityViolationException> { flush() } } 方法

我想您已经扩展了flush ...您可能想扩展CrudRepository

请参阅:What is difference between CrudRepository and JpaRepository interfaces in Spring Data JPA?


关于异常的说明

您期望抛出SQLException

但是请注意,将改为抛出DataIntegrityViolationException

请参阅:Consistent Exception Hierarchy