hibernate - CRUD 存储库不遵守 UNIQUE 约束

标签 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)

提前致谢!

最佳答案

发生这种情况是因为没有 insert声明发表。

Hibernate 不会 flush session 除非有充分的理由这样做

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

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

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

如何解决?

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

with (userCrudRepository) {
    save(testUserEntity)
    val newUserEntity = with (testUserEntity) { UserEntity.fromParameters(UUID.randomUUID().toString(), email, password, firstName, lastName) }
    save(newUserEntity)
    assertThrows<DataIntegrityViolationException> {
        flush()
    }
}

请注意,没有 flush CrudRepository 中的方法

我猜你已经扩展了 CrudRepository ...您可能想要扩展 JpaRepository相反。

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


异常注意事项

您期待一个 SQLException 被抛出。

但请注意 DataIntegrityViolationException 将被抛出。

参见:Consistent Exception Hierarchy

关于hibernate - CRUD 存储库不遵守 UNIQUE 约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56091934/

相关文章:

gradle - Gradle:使用一个任务禁用另一个任务

hibernate - org.hibernate.PropertyNotFoundException : Could not find setter for flat_rate on class dk. comtalk.billing.server.rating.db.RateDTO 问题

hibernate - Antlr识别异常

eclipse - Gradle boot创建的可执行jar重新打包缺少的jar

java - 如何使用 Spring Boot 查询和检索约 100 个客户数据库的结果?

kotlin - Kotlin 中 += 和添加到 MutableList 之间的区别

java - 通讯链路故障 : Connection reset with C3P0

hibernate - 尝试在域中查找空值时,grails方法缺少异常

java - 带有 Spring Boot 建议的 AOP 未触发

kotlin - 为什么使用 bylazy 会使我的 Kotlin 代码变慢