簡體   English   中英

Clojure中的數據庫函數式編程

[英]Database Functional Programming in Clojure

“如果你擁有的唯一工具是錘子,那就很誘人,把所有東西看作是釘子。” - 亞伯拉罕·馬斯洛

我需要編寫一個工具來將大型分層(SQL)數據庫轉儲到XML。 層次結構由具有輔助AddressPhone等表的Person表組成。

  • 我必須轉儲數千行,所以我想逐步這樣做,而不是將整個XML文件保存在內存中。

  • 我想將非純函數代碼隔離到應用程序的一小部分。

  • 我認為這可能是在Clojure中探索FP和並發性的好機會。 我還可以向持懷疑態度的同事展示不可變數據和多核利用的好處。

我不確定應用程序的整體架構應該如何。 我想我可以使用一個不純的函數來檢索數據庫行並返回一個惰性序列,然后可以由返回XML片段的純函數處理。

對於每個Person行,我可以創建一個Future並且有幾個並行處理(輸出順序無關緊要)。

在處理每個Person ,任務將從AddressPhone等表中檢索適當的行並生成嵌套的XML。

我可以使用通用函數來處理大多數表,依靠數據庫元數據來獲取列信息,並為需要自定義處理的少數表提供特殊功能。 這些函數可以在map(table name -> function)列出map(table name -> function)

我是否以正確的方式解決這個問題? 我可以輕松地使用Java在OO中執行此操作,但這並不好玩。

順便說一句,有沒有關於FP模式或架構的好書? 我有幾本關於Clojure,Scala和F#的好書,雖然每個都很好地涵蓋了語言,但沒有人看過功能編程設計的“大圖”。

好吧,很酷,你用這個作為展示Clojure的機會。 所以,你想要演示FP和並發性。 收到。

為了讓你的對話者驚嘆,我想說明一下:

  • 使用單個線程執行程序的性能。
  • 隨着線程數量的增加,程序的性能如何提高。
  • 將程序從單線程變為多線程是多么容易。

您可以創建一個函數將單個表轉儲到XML文件。

(defn table-to-xml [name] ...)

有了它,您可以計算出將關系數據轉換為XML的核心任務的全部或代碼。

現在你已經解決了核心問題,看看是否會增加更多的線程速度。

您可以修改table-to-xml以接受其他參數:

(defn table-to-xml [name thread-count] ...)

這意味着你有一個線程在一個表上工作。 在這種情況下,每個線程可能會處理每第n行。 將多個線程放在一個表上的問題是每個線程都想要寫入同一個XML文件。 這個瓶頸可能會讓這個策略變得毫無用處,但值得一試。

如果每個表創建一個XML文件是可以接受的,那么每個表生成一個線程可能很容易獲勝。

(map #(future (table-to-xml %)) (table-names))

在表,文件和線程之間只使用一對一的關系:作為指導,我希望你的代碼不包含任何refs或dosyncs,解決方案應該非常簡單。

一旦開始為每個表生成多個線程,就會增加復雜性,並且可能看不到性能的大幅提升。

在任何情況下,每個表可能會有一個或兩個查詢來獲取值和元數據。 關於不想在內存中加載所有數據的注釋:每個線程一次只能處理一行。

希望有所幫助!

鑒於您的評論,這里有一些可能有用的偽代碼:

(defn write-to-xml [person]
  (dosync
   (with-out-append-writer *path*
     (print-person-as-xml))))

(defn resolve-relation [person table-name one-or-many]
  (let [result (query table-name (:id person))]
    (assoc person table-name (if (= :many one-or-many)
                               result
                               (first result)))))

(defn person-to-xml [person]
  (write-to-xml
   (-> person
       (resolve-relation "phones" :many)
       (resolve-relation "addresses" :many))))

(defn get-people []
  (map convert-to-map (query-db ...)))

(defn people-to-xml []
  (map (fn [person]
         (future (person-to-xml %)))
       (get-people)))

您可以考慮使用Java executors庫來創建線程池。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM