datomic:交易功能并没有真正写入数据库
datomic: transact function not really writing to database
我是 运行 无数据的开发数据库
但是,我认为它会向数据库写入一些内容,但是当我拉取时,它不存在。这是我的 peer.clj
(ns dank.peer
(:require [datomic.api :as d :refer (q)]
[clojure.pprint :as pp]))
; Name the database as a uri
(def uri "datomic:mem://dank")
; Read the schema and seed data as strings
(def schema-tx (read-string (slurp "resources/dank/schema.edn")))
(def data-tx (read-string (slurp "resources/dank/seed-data.edn")))
; Initialize the db with above vars
(defn init-db
[]
(when (d/create-database uri)
(let
[conn (d/connect uri)]
@(d/transact conn schema-tx)
@(d/transact conn data-tx))))
(init-db)
(def conn (d/connect uri))
(def db (d/db conn))
(defn create
"Creates a new note"
[notes]
@(d/transact
conn
[{:db/id #db/id[:db.part/user]
:item/author "default"
:item/notes notes}]))
(defn get-notes
[author]
(d/pull-many db '[*]
(flatten (into []
(q '[:find ?e
:in $ ?author
:where
[?e :item/author ?author]]
db
author
)))))
(create "some note")
----> 显示整个交易数据结构前后。
(get-notes "default")
---> [] 是空的!
我是不是漏掉了什么?
t0,t1,t2表示递增时间t,其中t0先于t1,t1先于t2
(d/db conn)
return调用时数据数据库的当前快照。
假设您在 t0 中调用了 (def db (d/db conn))。在时间 t0,票据是空的。这里的数据库是数据库时间 t0 的快照。
然后您在时间 t1 期间使用 (create "some note") 创建了一些东西。在时间 t1,笔记至少包含 1 个笔记。
然后在时间 t2 期间你打电话 (get-notes "default")。在时间t2,笔记至少包含1个笔记。
问题是,get-notes
中的 db
仍然引用时间 t0
期间的数据库快照,即您使用 (def db (d/db conn))
检索的 db
t0
。在时间t0
,仍然没有笔记。这就是为什么 get-notes
return 为空。
当你查询一个数据数据库时,你必须指定你要查询的数据库:当前的数据库,昨天的数据库,1小时前的数据库等等。当然,获取数据库是很容易的现在,只需调用 (d/db conn)
.
我发现将 db 明确用于查询函数很有用,例如将 get-notes
函数声明参数更改为 (defn get-notes [db author] ....)
。
mavbozo 的回答是正确的,当您调用 get-notes
函数时,您使用的是交易新票据之前的数据库值。
如果您在 get-notes
之前再次调用 (def db (d/db conn))
,您将在数据库中看到新数据。
但是,通常最好避免将连接或数据库作为全局变量来处理,因为它会阻止函数行为严格根据其参数确定。如您所见,get-notes
的行为取决于全局状态中 db
变量的状态。根据经验,最好将数据库值传递给查询或从数据库中提取的函数,并将连接传递给对数据库进行事务处理或随时间监视数据库状态的函数(参见 http://docs.datomic.com/best-practices.html#consistent-db-value-for-unit-of-work更多关于 Datomic 数据库的单个值的讨论)。
在这种情况下,您的 get-notes
函数可能类似于:
(defn get-notes
[db author]
(d/q '[:find (pull ?e [*])
:in $ ?author
:where
[?e :item/author ?author]]
db
author))
然后您可以通过以下方式调用:
(get-notes (d/db conn) "default")
查询最新版本的数据库。这种方法还有一个优点,您可以使用任何数据库值(即最近的、过去给定时间的值或历史数据库)调用 get-notes
。
同样,我建议更改您的 create
函数以建立连接,而不是使用全局定义的连接。
就管理连接而言,最好还是尽可能避免使用全局变量。一些首选选项可能是将连接放入应用程序状态映射或适当地在整个程序中传递的原子中。另一个经常使用的好选择是利用 Stuart Sierra 的组件库 (https://github.com/stuartsierra/component) 来管理连接的生命周期。
我是 运行 无数据的开发数据库
但是,我认为它会向数据库写入一些内容,但是当我拉取时,它不存在。这是我的 peer.clj
(ns dank.peer
(:require [datomic.api :as d :refer (q)]
[clojure.pprint :as pp]))
; Name the database as a uri
(def uri "datomic:mem://dank")
; Read the schema and seed data as strings
(def schema-tx (read-string (slurp "resources/dank/schema.edn")))
(def data-tx (read-string (slurp "resources/dank/seed-data.edn")))
; Initialize the db with above vars
(defn init-db
[]
(when (d/create-database uri)
(let
[conn (d/connect uri)]
@(d/transact conn schema-tx)
@(d/transact conn data-tx))))
(init-db)
(def conn (d/connect uri))
(def db (d/db conn))
(defn create
"Creates a new note"
[notes]
@(d/transact
conn
[{:db/id #db/id[:db.part/user]
:item/author "default"
:item/notes notes}]))
(defn get-notes
[author]
(d/pull-many db '[*]
(flatten (into []
(q '[:find ?e
:in $ ?author
:where
[?e :item/author ?author]]
db
author
)))))
(create "some note")
----> 显示整个交易数据结构前后。
(get-notes "default")
---> [] 是空的!
我是不是漏掉了什么?
t0,t1,t2表示递增时间t,其中t0先于t1,t1先于t2
(d/db conn)
return调用时数据数据库的当前快照。
假设您在 t0 中调用了 (def db (d/db conn))。在时间 t0,票据是空的。这里的数据库是数据库时间 t0 的快照。
然后您在时间 t1 期间使用 (create "some note") 创建了一些东西。在时间 t1,笔记至少包含 1 个笔记。
然后在时间 t2 期间你打电话 (get-notes "default")。在时间t2,笔记至少包含1个笔记。
问题是,get-notes
中的 db
仍然引用时间 t0
期间的数据库快照,即您使用 (def db (d/db conn))
检索的 db
t0
。在时间t0
,仍然没有笔记。这就是为什么 get-notes
return 为空。
当你查询一个数据数据库时,你必须指定你要查询的数据库:当前的数据库,昨天的数据库,1小时前的数据库等等。当然,获取数据库是很容易的现在,只需调用 (d/db conn)
.
我发现将 db 明确用于查询函数很有用,例如将 get-notes
函数声明参数更改为 (defn get-notes [db author] ....)
。
mavbozo 的回答是正确的,当您调用 get-notes
函数时,您使用的是交易新票据之前的数据库值。
如果您在 get-notes
之前再次调用 (def db (d/db conn))
,您将在数据库中看到新数据。
但是,通常最好避免将连接或数据库作为全局变量来处理,因为它会阻止函数行为严格根据其参数确定。如您所见,get-notes
的行为取决于全局状态中 db
变量的状态。根据经验,最好将数据库值传递给查询或从数据库中提取的函数,并将连接传递给对数据库进行事务处理或随时间监视数据库状态的函数(参见 http://docs.datomic.com/best-practices.html#consistent-db-value-for-unit-of-work更多关于 Datomic 数据库的单个值的讨论)。
在这种情况下,您的 get-notes
函数可能类似于:
(defn get-notes
[db author]
(d/q '[:find (pull ?e [*])
:in $ ?author
:where
[?e :item/author ?author]]
db
author))
然后您可以通过以下方式调用:
(get-notes (d/db conn) "default")
查询最新版本的数据库。这种方法还有一个优点,您可以使用任何数据库值(即最近的、过去给定时间的值或历史数据库)调用 get-notes
。
同样,我建议更改您的 create
函数以建立连接,而不是使用全局定义的连接。
就管理连接而言,最好还是尽可能避免使用全局变量。一些首选选项可能是将连接放入应用程序状态映射或适当地在整个程序中传递的原子中。另一个经常使用的好选择是利用 Stuart Sierra 的组件库 (https://github.com/stuartsierra/component) 来管理连接的生命周期。