- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
“如果您拥有的唯一工具是锤子,那么将一切都当作钉子来对待是很诱人的。” - Abraham Maslow
我需要编写一个工具来将大型分层 (SQL) 数据库转储为 XML。该层次结构由一个 Person
表及其附属的 Address
、Phone
等表组成。
我必须转储数千 行,所以我想逐步转储,而不是将整个 XML 文件保存在内存中。
我想将非纯函数代码隔离到应用程序的一小部分。
我认为这可能是探索 Clojure 中的 FP 和并发的好机会。我还可以向持怀疑态度的同事展示不可变数据和多核利用的好处。
我不确定应用程序的整体架构应该如何。我在想我可以使用一个非纯函数来检索数据库行并返回一个惰性序列,然后可以由一个返回 XML 片段的纯函数进行处理。
对于每个 Person
行,我可以创建一个 Future
并并行处理多个(输出顺序无关紧要)。
在处理每个 Person
时,任务将从 Address
、Phone
等表中检索适当的行,并生成嵌套的XML。
我可以使用一个通用函数来处理大部分表,依靠数据库元数据来获取列信息,对少数需要自定义处理的表使用特殊函数。这些函数可以列在 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 个线程在一张表上工作。在这种情况下,每个线程可能会处理每第 n 行。将多个线程放在一个表上的一个问题是每个线程都将要写入同一个 XML 文件。该瓶颈可能会使该策略无用,但值得一试。
如果为每个表创建一个 XML 文件是可以接受的,那么为每个表生成一个线程可能会很容易。
(map #(future (table-to-xml %)) (table-names))
仅使用表、文件和线程之间的一对一关系:作为准则,我希望您的代码不包含任何引用或同步,并且解决方案应该非常简单。
一旦您开始为每个表生成多个线程,您就会增加复杂性并且可能看不到太多性能提升。
在任何情况下,您可能会对每个表进行一到两次查询以获取值和元数据。关于您不想将所有数据加载到内存中的评论:每个线程一次只能处理一行。
希望对您有所帮助!
鉴于您的评论,这里有一些伪代码可能会有所帮助:
(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 执行程序库来创建线程池。
关于Clojure 中的数据库函数式编程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4604149/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!