Clojure建立多个数据库连接

Clojure建立多个数据库连接

问题描述:

我们有一个Clojure Web应用程序,由多个项目(> 20)使用,它们有多个用户同时登录。所有项目都有自己的MySQL数据库。我们试图找出一种方法来使用一个应用程序实例来为来自其项目数据库的用户请求提供服务。Clojure建立多个数据库连接

以下脚本显示了我们的多个连接的原理,并且应该可以在REPL中执行(使用正确的数据库设置)。

(ns testmultiple.core 
    (:require 
    [clojure.java.jdbc :as jdbc] 
    [compojure.core :refer [defroutes GET ANY routes context]] 
    [conman.core :as conman] 
    [mount.core :refer [defstate]])) 

(def database-urls {:DB1 "jdbc:mysql://localhost:3306/DB1?user=DB1_user&password=DB1_password" 
        :DB2 "jdbc:mysql://localhost:3306/DB2?user=DB2_user&password=DB2_password"}) 

;; Connects to all databases in pool-specs 
(defn connect! 
    [pool-specs] 
    (reduce merge (map (fn [pool-spec] 
         {(keyword (key pool-spec)) (conman/connect! {:jdbc-url (val pool-spec)})}) pool-specs))) 

;; Disconnect from all databases in db-connections 
(defn disconnect! 
    [db-connections] 
    (map (fn [db] (conman/disconnect! (val db))) db-connections)) 

;; Establish connections to all databases 
;; and store connections in *dbs* 
(defstate ^:dynamic *dbs* 
      :start (connect! 
        database-urls) 
      :stop (disconnect! *dbs*)) 

;; Bind queries to *db* dynamic variable which is bound 
;; to each clients database before executing queries 
;; The queries file defines the query get-user which 
;; returns user by user id 
(def ^:dynamic *db* nil) 
(conman/bind-connection *db* "sql/queries.sql") 

(mount.core/start) 

; Define function that executes in current *db* binding 
(defn getuser [id] (get-user {:id id})) 

; Works, the user with Id 670 is returned from DB1 
(with-bindings {#'*db* (:DB1 *dbs*)} (getuser 670)) 

; Works, the user with Id 670 is returned from DB2 
(with-bindings {#'*db* (:DB2 *dbs*)} (getuser 670)) 

更具体地说,该项目是从路由器中的URL请求中推断出来的。以下代码显示了路由器的原理。访问www.example.com/DB1/page1和www.example.com/DB2/page2将分别显示来自DB1和来自DB2的数据的页1。

(defn serve-page1 [] (str "page1" (getuser 670))) 
(defn serve-page2 [] (str "page2" (getuser 670))) 

(def home-routes 
    (context "/:project" [project] 
    (if (contains? *dbs* (keyword project)) 
     (routes 
     (GET "/page1" [] 
      (with-bindings {#'*db* ((keyword project) *dbs*)} 
      (serve-page1))) 
     (GET "/page2" [] 
      (with-bindings {#'*db* ((keyword project) *dbs*)} 
      (serve-page2)))) 
     (ANY "*" [] (str "Project not found"))))) 

这将是一个具有相当流量的应用程序。值得注意的是,我们仍处于开发阶段,因此无法使用本地主机上运行的多个数据库来测试此解决方案。我们的问题是

  • 正在建立像这样合理,稳定和可扩展的多个连接?
  • 有没有其他更好的方法来路由和动态绑定项目的数据库?

正在建立像这样合理,稳定和可扩展的多重连接吗?

是的,这是一个非常合理的方法。很少数据库系统受到传出连接数量的限制。 JDBC和Korma都会在clojure中处理这个问题。您确实需要了解哪些请求取决于在构建监视和操作相关组件时使用哪个数据库。所以你可以知道哪个数据库导致了问题。

是否还有其他更好的方法用于项目数据库的路由和动态绑定?

我唯一的建议是明确地将数据库传递给每个函数,而不是使用绑定,虽然这是个人风格的意见,你的方法将明确工作。

+0

谢谢你的回应!我来自PHP,每次发出http请求时都会重新建立数据库连接,因此长期持续连接的想法对我来说是新的。连接是否有任何风险?如果是这样 - 它会自动重新建立还是必须进行监控?解释如何建立和维护连接的任何链接都非常出色。 –