簡體   English   中英

為什么@Transactional 和@Rollback 不起作用?

[英]Why @Transactional and @Rollback don't work?

我正在使用帶有 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 文檔指出:

指示在測試方法完成后是否應回滾事務測試方法的事務。 如果為 true,則事務回滾; 否則,事務被提交(另見@Commit)。 即使未顯式聲明 @Rollback,Spring TestContext Framework 中集成測試的回滾語義也默認為 true。

當聲明為類級別注釋時,@Rollback 為測試類層次結構中的所有測試方法定義默認回滾語義。 當聲明為方法級別的注解時,@Rollback 為特定的測試方法定義了回滾語義,可能會覆蓋類級別的 @Rollback 或 @Commit 語義。

請參考: https : //docs.spring.io/spring/docs/4.2.5.RELEASE/spring-framework-reference/html/integration-testing.html#testcontext-tx

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM