我试图直接使用Clojure的hashmap和MapDB,并遇到了奇怪的行为。我检查了Clojure和MapDB源代码,无法理解这个问题。
首先一切看起来都很好:
lein try org.mapdb/mapdb "1.0.6"
; defining a db for the first time
(import [org.mapdb DB DBMaker])
(defonce db (-> (DBMaker/newFileDB (java.io.File. "/tmp/mapdb"))
.closeOnJvmShutdown
.compressionEnable
.make))
(defonce fruits (.getTreeMap db "fruits-store"))
(do (.put fruits :banana {:qty 2}) (.commit db))
(get fruits :banana)
=> {:qty 2}
(:qty (get fruits :banana))
=> 2
(first (keys (get fruits :banana)))
=> :qty
(= :qty (first (keys (get fruits :banana))))
=> true
CTRL-D
=> Bye for now!
然后我尝试再次访问数据:
lein try org.mapdb/mapdb "1.0.6"
; loading previsously created db
(import [org.mapdb DB DBMaker])
(defonce db (-> (DBMaker/newFileDB (java.io.File. "/tmp/mapdb"))
.closeOnJvmShutdown
.compressionEnable
.make))
(defonce fruits (.getTreeMap db "fruits-store"))
(get fruits :banana)
=> {:qty 2}
(:qty (get fruits :banana))
=> nil
(first (keys (get fruits :banana)))
=> :qty
(= :qty (first (keys (get fruits :banana))))
=> false
(class (first (keys (get fruits :banana))))
=> clojure.lang.Keyword
对于=
,相同的关键字怎么会有所不同?
是否有一些奇怪的参考问题发生?
答案 0 :(得分:2)
问题是由关键字的平等工作方式引起的。看着
=
function的实施我们看到,因为关键字不是
clojure.lang.Number
或clojure.lang.IPersistentCollection
他们的平等
根据{{1}}方法确定。略过source of
clojure.lang.Keyword
我们了解到关键字不会覆盖
Object.equals
因此两个关键字相等,如果它们相同
对象
MapDB的默认序列化程序是Object.equals
,它的子类
org.mapdb.SerializerPojo
。在its documentation我们可以读到这一点
它是
Serializer,它使用'header byte'来序列化/反序列化大多数类 来自'java.lang'和'java.util'包。
不幸的是,它对org.mapdb.SerializerBase
类的效果不佳;它没有
保留关键字的身份,从而打破平等。
为了解决这个问题,让我们尝试使用。编写自己的serializer
EDN format - 或者,您可以考虑使用Nippy - 并使用
它在我们的MapDB中。
clojure.lang
在定义了(require '[clojure.edn :as edn])
(deftype EDNSeralizer []
;; See docs of org.mapdb.Serializer for semantics.
org.mapdb.Serializer
(fixedSize [_]
-1)
(serialize [_ out obj]
(.writeUTF out (pr-str obj)))
(deserialize [_ in available]
(edn/read-string (.readUTF in)))
;; MapDB expects serializers to be serializable.
java.io.Serializable)
(def edn-serializer (EDNSeralizer.))
(import [org.mapdb DB DBMaker])
(def db (.. (DBMaker/newFileDB (java.io.File. "/tmp/mapdb"))
closeOnJvmShutdown
compressionEnable
make))
(def more-fruits (.. db
(createTreeMap "more-fruits")
(valueSerializer (EDNSeralizer.))
(makeOrGet)))
(.put more-fruits :banana {:qty 2})
(.commit db)
的JVM中重新打开more-fruits
树映射后
存储在其中的EDNSeralizer
对象将与任何其他:qty
相同的对象
实例。因此,相等检查将正常工作。