我有以下 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 除非有充分的理由这样做。
-
@DataJpaTest
是@Transactional
.这意味着交易 a@Test
其中执行的方法在方法返回后回滚。 -
UserEntity
映射还鼓励 hibernate 延迟insert
(尝试在@GeneratedValue(strategy = IDENTITY)
属性上使用id
来强制发出insert
s)
运行测试时会发生以下情况,不要深入细节:
- Spring 的测试基础设施
begin
交易 -
@Test
方法运行 -
save(testUserEntity)
- Hibernate 意识到没有理由访问数据库并延迟insert
-
shouldThrow<SQLException> { save(newUserEntity) }
- 和以前一样 -
@Test
方法返回 - 事务回滚。 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
将被抛出。
关于hibernate - CRUD 存储库不遵守 UNIQUE 约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56091934/