kotlin - Kotlin 和 Arrow.io:使用 IO.bracketCase 进行交易
问题描述
我目前正在 Kotlin 中使用 Arrow.io,我很想在工作项目中使用该库(与 Spring Boot 一起)。我不太清楚如何正确解决的一个问题是事务管理。IO<A>.bracketCase(...)
在我看来,这是完成这项工作的正确工具。这是我目前正在研究的方法:
interface TransactionProvider {
fun startTransaction(): IO<Transaction>
}
interface Transaction {
fun commit(): IO<Unit>
fun rollback(): IO<Unit>
}
fun <A> TransactionProvider.runInTransaction(action: IO<A>): IO<A> =
startTransaction()
.bracketCase(::releaseTransaction) { action }
fun releaseTransaction(t: Transaction, exitCase: ExitCase<Throwable>): IO<Unit> =
when (exitCase) {
is ExitCase.Completed -> t.commit()
else -> t.rollback()
}
可悲的是,它并没有像我期望的那样工作:当在执行期间抛出异常时action
,我希望回滚。但事实并非如此(例如,以下测试失败):
@Test
internal fun `transaction rolls back on failure`() {
val transaction: Transaction =
mock {
on { commit() } doReturn IO.unit
on { rollback() } doReturn IO.unit
}
val transactionProvider: TransactionProvider =
mock{
on { startTransaction() } doReturn IO.just(transaction)
}
val exception = IllegalArgumentException("Here I am!")
val action = IO{ throw exception }
val result: Either<Throwable, Unit> =
transactionProvider
.runInTransaction(action)
.attempt()
.unsafeRunSync()
assertThat(result).isEqualTo(exception.left())
verify(transaction, never()).commit()
verify(transaction, times(1)).rollback()
}
我现在经常玩这个,无论我如何安排我的类型以及我将action
问题放在哪里 - 我永远不会bracketCase
回滚我的交易。我究竟做错了什么?有没有更好的方法来做到这一点?如果可能的话,我更喜欢不使用类型安全的方式unsafeRun
。
解决方案
我认为除了测试代码之外,您的一切都是正确的——也许模拟程序无法正常使用IO
. 例如,以下测试代码使用第一个片段中的 Transaction 定义按预期工作:
fun main(args: Array<String>): Unit {
val transactor = object: Transaction {
override fun commit(): IO<Unit> = IO { println("Commit"); }
override fun rollback(): IO<Unit> = IO { println("Rollback"); }
}
val txProvider = object: TransactionProvider {
override fun startTransaction(): IO<Transaction> = IO.just(transactor)
}
val actionThrow = IO { println("Throwing"); throw IllegalArgumentException("Exception!") }
val actionSuccess = IO { println("Returning value"); 2 }
val resultThrow = txProvider.runInTransaction(actionThrow).attempt().unsafeRunSync()
println(resultThrow)
val resultSuccess = txProvider.runInTransaction(actionSuccess).attempt().unsafeRunSync()
println(resultSuccess)
}
我得到的输出如下:
Throwing
Rollback
Left(a=java.lang.IllegalArgumentException: Exception!)
Returning value
Commit
Right(b=2)
这正是我期望使用#bracketCase
. (这是使用箭头 0.10.0-SNAPSHOT。)
推荐阅读
- python - 如何在 vscode 的仅检查模式下运行 black/isort?
- laravel - 将数据语言从 wordpress 发送到 laravel
- migration - 移动不同版本的shopware内容
- mysql - 如何在 Kubernetes 中禁用 mysql 严格模式?
- javascript - 如何更改jQuery生成的输入框中的值?
- flutter - 颤振http,如何防止在chrome上跟随重定向
- odoo-enterprise - Linux VPS服务器中odoo15企业版安装
- regex - apache mod_rewrite 更改深度链接中的基本 URL
- java - 在 setOnClickListener 上共享图像和文本
- github - 如何将我的 GitHub Enterprise 帐户与 Visual Studio Code 连接