CRUD 存储库不遵守 UNIQUE 约束 [英] CRUD repository does not respect UNIQUE constraint
问题描述
我有以下 JPA 实体
I have the following JPA entity
@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 约束的测试,插入具有相同电子邮件的另一个用户.
And this is my test to check the UNIQUE constraint, inserting another user with the same email.
@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) }
}
}
}
新实体总是被插入重复的电子邮件,而不会抛出任何异常.
The new entity always gets inserted with a duplicate email without any exception being thrown.
Expected exception java.sql.SQLException but no exception was thrown
我可以在日志中看到使用给定的约束正确创建了表.
I can see in the log that the table is created correctly with the given constraint.
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
语句.
This happens because no insert
statement issued.
Hibernate 不会flush
会话除非有充分的理由这样做.
Hibernate does not flush
session unless it has a good reason to do so.
@DataJpaTest
是@Transactional
.这意味着在方法返回后回滚@Test
方法中执行的事务.UserEntity
映射还鼓励休眠延迟insert
(尝试在id
上使用@GeneratedValue(strategy = IDENTITY)
code> 属性强制发出insert
s)
@DataJpaTest
is@Transactional
. This means that the transaction a@Test
method executed within is rolled back after the method returns.UserEntity
mapping also encourages hibernate to delay theinsert
(try using@GeneratedValue(strategy = IDENTITY)
onid
property to force issuinginsert
s)
不要深入研究太多细节,运行测试时会发生以下情况:
Not diving into too much details the following happens when you run test:
- Spring 的测试基础架构
begin
的事务 @Test
方法运行save(testUserEntity)
- Hibernate 意识到没有理由命中数据库并延迟insert
shouldThrow
- 与之前相同{ save(newUserEntity) } @Test
方法返回- 事务回滚.Hibernate 确实执行
insert
s,因为没有理由这样做.
- Spring's test infrastructure
begin
s transaction @Test
method runssave(testUserEntity)
- Hibernate realizes that there is no reason to hit the database and delays theinsert
shouldThrow<SQLException> { save(newUserEntity) }
- same as previous@Test
method returns- Transaction rolls back. Hibernate does execute
insert
s because there is no reason to.
如何解决?
最简单的方法是使用 JpaRepository#flush
:
with (userCrudRepository) {
save(testUserEntity)
val newUserEntity = with (testUserEntity) { UserEntity.fromParameters(UUID.randomUUID().toString(), email, password, firstName, lastName) }
save(newUserEntity)
assertThrows<DataIntegrityViolationException> {
flush()
}
}
Note that there is no flush
method in CrudRepository
我猜你已经扩展了 CrudRepository
... 你可能想要扩展 JpaRepository
.
I guess that you have extended CrudRepository
... You may want to extend JpaRepository
instead.
参见:CrudRepository 和 JpaRepository 有什么区别Spring Data JPA 中的接口?
异常注意事项
您正在等待 SQLException
被抛出.
You are expecting an SQLException
to be thrown.
但请注意DataIntegrityViolationException
将被抛出.
But note that DataIntegrityViolationException
will be thrown instead.
参见:一致异常层次结构
这篇关于CRUD 存储库不遵守 UNIQUE 约束的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!