java - 为什么@Transactional 和@Rollback 不起作用?
问题描述
我正在使用带有 Kotlin 的 Spring Boot,而我使用的数据库是 PostgreSQL。当我编写测试时,我发现它@Rollback
不起作用。
application-test.properties
# Database configuration
spring.datasource.url=jdbc:postgresql://localhost:5432/magnus
spring.datasource.username=postgres
spring.datasource.password=123456
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
spring.jpa.database=POSTGRESQL
IUserInfoRepository.java
interface IUserInfoRepository : JpaRepository<UserInfo, UUID> {
fun findByUserName(name: String): UserInfo?
@Transactional
fun deleteByUserName(name: String): Int
}
UserService.java
@Service
class UserService(@Autowired val userInfoRepository: IUserInfoRepository) {
private lateinit var user: User
fun initService(user: User) {
this.user = user;
}
fun createUser(userName: String, password: ByteArray, nickName: String, isAdmin: Boolean): Boolean {
if (userInfoRepository.findByUserName(userName) != null) {
return false
}
val hashCodeTable = HashCodeTable(RandomStringUtils.randomAscii(16).toByteArray())
val hashedPassword = genHashedPassword(password, hashCodeTable.salt1)
userInfoRepository.save(UserInfo(userName, nickName, hashedPassword, hashCodeTable, isAdmin))
return true
}
fun deleteUser(): Boolean {
return validateUserAndDo {
userInfoRepository.deleteByUserName(user.userName)
true
}
}
fun findUser(): UserInfo? {
return userInfoRepository.findByUserName(user.userName)
}
fun validateUser(): Boolean {
return (findUser()?.hashedPassword?.contentEquals(user.password)) ?: false
}
fun getLoginSalt(userName: String): ByteArray {
return userInfoRepository.findByUserName(userName)?.hashCodeTable?.salt1 ?: ByteArray(0)
}
fun changePassword(newPassword: ByteArray): Boolean {
return validateUserAndDo() {
val oldUser = findUser()!!
val hashedPassword = genHashedPassword(newPassword, oldUser.hashCodeTable.salt1)
val newUser = UserInfo(oldUser.userName, oldUser.nickName, hashedPassword, oldUser.hashCodeTable, oldUser.isAdmin, oldUser.subscriptionTable, oldUser.id, oldUser.categoryTables)
userInfoRepository.save(newUser)
true
}
}
private fun validateUserAndDo(something: () -> Boolean): Boolean {
if (validateUser()) {
return something.invoke()
}
return false
}
fun changeNickName(newNickName: String): Boolean {
return validateUserAndDo() {
val oldUser = findUser()!!
val newUser = UserInfo(oldUser.userName, newNickName, oldUser.hashedPassword, oldUser.hashCodeTable, oldUser.isAdmin, oldUser.subscriptionTable, oldUser.id, oldUser.categoryTables)
userInfoRepository.save(newUser)
true
}
}
fun changePermission(isAdmin: Boolean): Boolean {
return validateUserAndDo() {
val oldUser = findUser()!!
val newUser = UserInfo(oldUser.userName, oldUser.nickName, oldUser.hashedPassword, oldUser.hashCodeTable, isAdmin, oldUser.subscriptionTable, oldUser.id, oldUser.categoryTables)
userInfoRepository.save(newUser)
true
}
}
fun isPermission(): Boolean {
return userInfoRepository.findByUserName(user.userName)?.isAdmin ?: false
}
fun deleteAll(): Boolean {
userInfoRepository.deleteAll()
return true
}
}
UserServiceTest.java
@SpringBootTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class UserServiceTest(@Autowired val userService: UserService) {
private lateinit var userName: String
private lateinit var password: ByteArray
@BeforeAll
fun beforeTest() {
userName = "test"
password = "123456".toByteArray()
userService.createUser(userName, password, "Test", false)
val user = User(userName, genHashedPassword(password, userService.getLoginSalt(userName)))
userService.initService(user);
}
@Test
@Rollback
fun `delete user`() {
userService.deleteUser()
Assertions.assertNull(userService.findUser())
}
@Test
@Rollback
fun `get login salt`() {
Assertions.assertEquals(userService.getLoginSalt(userName).contentEquals(ByteArray(0)), false)
}
@Test
@Rollback
fun `validate User`() {
Assertions.assertEquals(userService.validateUser(), true)
}
}
解决方案
关于@Transactional,Spring 文档指出:
使用 @Transactional 注释测试方法会导致测试在事务中运行,默认情况下,测试完成后会自动回滚。如果测试类使用@Transactional 注释,则该类层次结构中的每个测试方法都将在事务中运行。未使用 @Transactional 注释的测试方法(在类或方法级别)将不会在事务中运行。
关于 @Rollback 注释,Spring 文档指出:
指示事务测试方法的事务是否应在测试方法完成后回滚。如果为真,则事务回滚;否则,事务被提交(另见@Commit)。Spring TestContext Framework 中集成测试的回滚语义默认为 true,即使 @Rollback 没有显式声明。
当声明为类级别注释时,@Rollback 为测试类层次结构中的所有测试方法定义默认回滚语义。当声明为方法级注释时,@Rollback 为特定测试方法定义回滚语义,可能会覆盖类级 @Rollback 或 @Commit 语义。
推荐阅读
- windows - 如何获取工作目录中文件名超过30个字符的文件名写入文本文件?
- python - 在列表列表中查找单词
- gitlab - 如何将 Jira Atlassian 与 GitLab 云集成?
- angular - Angular 6 路径参数问题
- python - 使用 Matplotlib 绘制决策边界时出错
- python - NameError:名称“单独”未在第 99 行定义
- batch-file - 如何缩短重复的表达式?
- azure - Azure 部署槽之间存在什么隔离级别?
- python - BeautifulSoup,1 个元素有 2 个相同的链接,如何只打印 1 个?
- php - Wordpress 自定义不起作用 - load-scripts.php 错误