我将Clojure与JDBC结合使用,以便在响应事件时从两个不同的数据库(特别是MySQL和Vertica)中选择记录并将其插入两个数据库中。我希望所有这些操作都在一个事务中进行,如果任何一条命令出了问题,都可以将其回滚。

(defn handle-request
  [request]
  (jdbc/with-db-transaction [mysql-conn config/mysql-db-spec]
    (jdbc/with-db-transaction [vertica-conn config/vertica-db-spec]
      (let [record (query-some-data mysql-conn request)]
        (update-some-data! mysql-conn record)
        (insert-some-vertica-data! vertica-conn record)))))

我担心这会冒着Vertica交易成功的风险,而不是MySQL交易的风险。 Clojure处理该操作的最惯用方式是什么?

最佳答案

事务是数据库提供的行为,而不是您用于从数据库发送/检索数据的编程语言提供的行为。因此,答案是您无法进行“真实”交易,因为无法协调两个数据库。

  • 我认为这里最简单的方法是先执行mysql tx,因为更新是看起来可能失败的唯一部分。然后,如果成功,则将其插入vertica,因为插入新数据是(或应该是)非常安全的。所以看起来像(伪代码):
  • (perform mysql tx)
    if (successful) then
      (do vertica tx)
    
  • 一个更复杂的解决方案是尝试自己执行事务/回滚行为,如下所示:
  • (do tx in DB 1)
    (try
      (do tx is DB 2)
      (catch Exception ex
        (rollback tx in DB 1)))
    

    但是,这不是最佳选择,因为您现在是自己编写一个本地数据库插件,而不是利用数据库的内置稳定性和可靠性(即如果catch子句完成运行之前出现问题怎么办?)。
  • 例如,如果您使用的是PostgreSQL,则可以找到一个外来数据包装程序(FDW)模块,该模块可以为您处理解决方案2。例如,postgres能够将Oracle DB视为“外部”表,并提供所有正常的DB保证人。它只比普通表慢一点。
  • 09-11 18:53
    查看更多