【问题标题】:Clojure JDBC Different DB Connections in One TransactionClojure JDBC 一个事务中的不同数据库连接
【发布时间】:2015-09-13 15:55:24
【问题描述】:

我正在使用带有 JDBC 的 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 方式是什么?

【问题讨论】:

  • 听起来你基本上想要2-phase XA transactions。 JTA 为分布式事务提供 Java API,但两个数据库都必须支持该协议,并且您必须在提供 JTA 事务管理器的应用程序服务器中运行,或者您必须嵌入自己的一个。 AFAIK,没有任何 Clojure 项目可以为您提供此功能。

标签: java jdbc clojure transactions database-connection


【解决方案1】:

事务是数据库提供的一种行为,而不是您用来从数据库发送/检索数据的编程语言。所以,答案是你不能有一个“真正的”事务,因为没有办法协调这 2 个数据库。

  1. 我认为这里最简单的方法是先执行 mysql tx,因为更新是唯一看起来可能会失败的部分。然后,如果成功,请插入 vertica,因为插入新数据是(或应该)非常安全的。所以它看起来像(伪代码):
(perform mysql tx) 
if (successful) then 
  (do vertica tx)
  1. 更复杂的解决方案是尝试自己执行事务/回滚行为,如下所示:
(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 DB 视为“外部”表并提供所有正常的 DB 保证。它只是比普通桌子慢一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-22
    • 1970-01-01
    • 1970-01-01
    • 2017-02-21
    相关资源
    最近更新 更多