Clojure JDBC 一个事务中的不同数据库连接

Clojure JDBC Different DB Connections in One Transaction

我在 JDBC 到 select 中使用 Clojure,并在响应事件时从两个不同的数据库(特别是 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 方法是什么?

事务是由数据库提供的一种行为,而不是由您用来 send/retrieve 来自数据库的数据的编程语言提供的。因此,答案是您无法进行 "real" 事务,因为无法协调 2 个数据库。

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

然而,这是次优的,因为您现在正在自己编写一个本地数据库插件,而不是利用数据库的内置稳定性和可靠性(即如果在 catch 子句完成之前出现问题怎么办运行?).

  1. 例如,如果您使用的是 PostgreSQL,您可能会找到可以为您处理解决方案 #2 的外部数据包装器 (FDW) 模块。例如,postgres 能够将 Oracle 数据库视为 "foreign" table 并提供所有正常的数据库保证。它只是比正常的 table.
  2. 慢一点