首页 > 解决方案 > Spring事务传播和隔离

问题描述

关于这个话题有很多问题。我通过堆栈交换搜索找到一个与我相同的问题,但没有找到任何问题。如果这个问题已经被问过,请原谅。

我的问题是:当使用 Spring 事务管理时,当具有 SERIALIZABLE 隔离的事务方法调用另一个具有 REQUIRES_NEW 传播的事务方法时会发生什么?

据我了解,可序列化隔离意味着任何事务都会完全锁定表,直到完成。同时,REQUIRES_NEW 将进行新事务并暂停现有事务。这意味着由于父方法还没有完成它的事务,它调用的方法会立即死锁。

我这里的理解错了吗?

为了说明,我在 Kotlin 中做了一个例子,它在 spring 中运行没有错误,即使它不应该,根据我的理解:

open class DummyApplication(val database: Database) {

    @Transactional(isolation = Isolation.SERIALIZABLE)
    open fun doThing() {

        val item = Item("1", "accountId1", "reference1")
        database.saveItemWithoutTransaction(item)

        val item2 = Item("2", "accountId2", "reference2")

        // This call should be instantly deadlocked because it tries to start a new transaction.
        database.saveItemWithTransaction(item2)

    }

}

和数据库:

@Repository
class JdbcDatabase(
        private val itemRepository: ItemRepository
) : Database {

    override fun saveItemWithoutTransaction(item: Item) {
        itemRepository.save(item.toItemEntity())
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    override fun saveItemWithTransaction(item: Item) {
        itemRepository.save(item.toItemEntity())
    }
}

itemRepository 是一个 Spring JPA 存储库,如果相关的话。

标签: springkotlintransactionsisolation-leveltransaction-isolation

解决方案


这取决于。

当具有 SERIALIZABLE 隔离的事务方法调用另一个具有 REQUIRES_NEW 传播的事务方法时会发生什么?

你的问题比你的例子更笼统。这就是为什么答案取决于

A)如果第一个事务改变了任何东西并且嵌套事务试图改变同一张表并且嵌套事务的隔离是READ_COMMITTED或更高(REPEATABLE_READ,SERIALIZABLE),那么嵌套事务将被阻塞。通常阻塞(在这种情况下为死锁)发生在嵌套事务刷新其数据的那一刻。

B)如果第一个事务在调用嵌套事务之前没有改变任何东西(在同一张表中)并且嵌套事务隔离是READ_COMMITTED或SERIALIZABLE,那么嵌套事务将不会被阻塞

C) 如果第一个事务改变了任何东西,并且嵌套事务试图改变同一张表并且嵌套事务的隔离为 READ_UNCOMMITTED,那么嵌套事务将不会被阻塞

您的示例对应于案例 A。这就是嵌套事务将被阻塞并发生死锁的原因。


推荐阅读