Clojure datomic:transact函数没有真正写入数据库
我正在用datomic free运行dev db 然而,我认为它会向数据库写入一些内容,但当我执行拉操作时,它不在那里。这是我的同龄人Clojure datomic:transact函数没有真正写入数据库,clojure,datomic,Clojure,Datomic,我正在用datomic free运行dev db 然而,我认为它会向数据库写入一些内容,但当我执行拉操作时,它不在那里。这是我的同龄人 (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 see
(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
)))))
(创建“一些注释”)
--->显示整个事务数据结构以及前后
(获取注释“默认值”)
-->[]它是空的
我在这里遗漏了什么吗?t0,t1,t2表示时间t的增加,其中t0在t1之前,t1在t2之前
(d/db conn)
在调用时返回datomic数据库的当前快照
假设您在t0中调用了(defdb(d/dbconn))。在时间t0,笔记是空的。这里的数据库是数据库时间t0的快照
然后在时间t1期间使用(创建“一些注释”)创建一些内容。在时间t1,注释至少包含1个注释
然后在t2期间调用(获取注释“默认”)。在时间t2,注释至少包含1个注释
问题是,get notes
内部的db
仍然引用时间t0
期间的数据库快照,即使用(def db(d/db conn))
在t0
检索的db
。在时间t0
,仍然没有注释。这就是为什么get notes
returnempty
当您查询datomic数据库时,必须指定要查询的数据库:现在的数据库、昨天的数据库、1小时前的数据库等等。当然,现在很容易获得数据库,只需调用(d/db conn)
我发现将db显式化对于查询函数非常有用,例如将
get notes
函数声明参数更改为(defn get notes[db author]..)
mavbozo的回答是正确的,当您调用get notes
函数时,您使用的是处理新便笺之前的数据库值
如果在获取注释之前再次调用(def db(d/db conn))
,您将在数据库中看到新数据
但是,通常最好避免将连接或数据库作为全局变量处理,因为这样可以防止函数行为严格根据其参数确定。正如您所注意到的,get notes
的行为取决于全局状态中db
变量的状态。根据经验,最好将数据库值传递给查询或从数据库中提取的函数,并将连接传递给对数据库进行事务处理的函数,或随时间监视数据库状态的函数(有关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
函数以建立连接,而不是使用全局定义的conn
至于管理连接,最好尽可能避免使用全局变量。一些首选选项可能是将连接放入应用程序状态映射或在程序中传递的原子(视情况而定)。另一个经常使用的好方法是利用Stuart Sierra的组件库()来管理连接的生命周期。您的获取注释
函数中的db
是什么?它应该类似于(d/db conn)
。此外,您可以避免平展、插入、拉出许多,只需在查询中执行以下操作::find[(pull?e[*])…]
@Andre我编辑了问题以包含这些内容。你在哪里找到的?我看了一下文档,发现了很多,经过努力,我能够将hashset转换成一个向量并将其展平……在获取注释中使用(d/db conn)
而不是db
。我目前没有时间给出一个恰当的、冗长的回答。但是现在这会让你重新开始。但是它不是已经在上面定义了(defdb(d/dbconn))这是相同的东西吗?哦!有没有更多关于这方面的文档,我似乎错过了这个非常重要的概念。所以基本上是这样做的(getnotesdbauthor)
,并传入一个新的(defdbd/dbconn)
?或者只需使用(d/db conn)
内部获取注释
@user299709我从以下官方教程@user299709中获得了这一重要概念,因为datomic查询只需要db而不需要连接,我更喜欢只传递db来获取注释功能。您可以在get notes函数之外检索数据库。这是一个更好、更全面的答案。还有一个问题,conn只是表示到数据库的连接,所以它没有任何多状态,并且是常量?那么initdb
我是否每次都需要为数据库设置种子,并且当repl断开连接时是否所有内容都丢失了?无论如何,为了加快启动时间,脚本通过lein exec-p src/dank/peer.clj运行需要20多秒