【问题标题】:Scala Asynchronous Database CallsScala 异步数据库调用
【发布时间】:2015-05-24 17:43:46
【问题描述】:

我目前正在使用 Slick 3.x.x,它在对数据库的所有调用中都是完全异步的。比方说,我有一个具有某种版本控制的表。每次我从已经存在的条目创建新条目(即更新给定条目)时,我必须确保增加版本号。

在这个异步的数据库通信世界中,我如何确保我可以保持数据完整性?在我使用版本控制的情况下,我会首先选择最大版本,这会给我一个 Future,然后我使用这个 Future 的结果,递增 1 并发出一个创建命令!

很有可能线程 1 以 select max version 开始并暂停了一段时间,满足新请求的线程 2 可以运行 select for max version 并递增并在数据库中写入新记录。现在 thread1 回来并尝试执行相同的进程,但结果只是导致 thread1 会覆盖 thread2 在数据库中写入的内容。

这可能是因为多个期货的运行顺序可能不同,所以我最终可能会有多个重复!

【问题讨论】:

    标签: database postgresql scala asynchronous slick


    【解决方案1】:

    应用程序管理其与数据库交互的异步性不会改变数据库事务的语义。如果你想要原子的、一致的操作序列,那么你需要一个数据库事务。光滑的offers 一个名为transactionally 的“组合器”,它将强制在数据库事务中运行一系列操作。

    【讨论】:

    • 感谢指向“事务性”的指针。在文档中,我可以看到有这样一个警告:“警告:- 不能保证失败在事务包装的单个 DBIOAction 级别是原子的,所以你不应该应用错误恢复组合器那个点。一个实际的数据库事务是在最外层的事务操作中创建和提交/回滚的。我无法完全理解它。谁能解释一下?
    • 假设您有多个 DBIOAction,我们称它们为 action1action2。您可以将它们与action1 andThen action2 串在一起。假设你做了(action1.transactionally andThen action2).transactionally 嵌套事务语义不能保证得到支持,所以这可能等同于(action1 andThen action2).transactionally。所以像(action1.transactionally.cleanUp(...) andThen action2).transactionally 这样的构造在回滚后可能无法清理。不过(action1 andThen action2).transactionally.cleanUp(...) 会抓住他们。
    • 说,我有 (action1 andThen action2).transactionally 为表中的列生成版本号 2,另一个执行包含我的两个操作的相同方法的线程将看到 2 或可能 3 或甚至 1 的版本号?既然 (action1 andThen action2).transactionally 的结果返回了一个 Future,那么如何保证另一个 Future 看到的数据是它之前的 Future 的结果呢?
    • 如果两个执行发生干扰,则保证其中一个事务失败。也就是说,如果 transaction1 读取 1 然后更新以将其增加到 2,并且 transaction2 恰好在 transactions1 的读取和更新之间读取,因此它也读取 1 然后还尝试更新到 2,两个事务之一将失败。如果每次执行都包装在一个未来中,那么其中一个未来将在失败状态下完成。然后你就知道了!
    • 好的,我明白了!所以看起来像在我所有的操作之外使用事务似乎是要走的路!
    猜你喜欢
    • 1970-01-01
    • 2018-04-12
    • 2015-05-13
    • 1970-01-01
    • 1970-01-01
    • 2017-02-03
    • 1970-01-01
    • 2012-07-19
    • 2015-06-19
    相关资源
    最近更新 更多