Datomic简介

“Datomic是一种以简单服务组合为设计目标的新数据库”,作者是Rich Hickey(同时也是Clojure的作者)。
本文介绍的是Datomic免费版本的使用和示例程序的解读,适用于有一些Clojure基础的用户。如果希望对Datomic的原理有些理解,可能直接跳到参考文献。
感谢焦向同学推荐的系统。

下载

下载版本:0.9.5372

1
2
unzip datomic-free-0.9.5372.zip
cd datomic-free-0.9.5372

交互式命令

使用repl创建内存数据库玩耍

1
2
cd ~/datomic-free-0.9.5372
./bin/repl

以下是samples/seattle/getting-started.clj中的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(use '[datomic.api :only [q db] :as d])
(def db-uri "datomic:mem://hello")
(d/create-database db-uri)
(def conn (d/connect db-uri))
(def schema-tx (read-string (slurp "samples/seattle/seattle-schema.edn")))
@(d/transact conn schema-tx)
(def data-tx (read-string (slurp "samples/seattle/seattle-data0.edn")))
@(d/transact conn data-tx)
(def results (q '[:find ?c :where [?c :community/name]] (db conn)))
(count results)
(def id (ffirst results))
(def entity (-> conn db (d/entity id)))
(keys entity)
(:community/name entity)

创建项目

如果需要在Java/Clojure工程里面使用datmoic,首先需要安装datomic-free二方包到本地:

1
2
3
4
5
6
7
8
cd ~/datomic-free-0.9.5372
./bin/maven-install
Installing datomic-free-0.9.5372 in local maven repository...
...
[INFO] Installing /Users/fenqi/Downloads/datomic-free-0.9.5372/datomic-free-0.9.5372.jar to /Users/fenqi/.m2/repository/com/datomic/datomic-free/0.9.5372/datomic-free-0.9.5372.jar
[INFO] Installing /Users/fenqi/Downloads/datomic-free-0.9.5372/pom.xml to /Users/fenqi/.m2/repository/com/datomic/datomic-free/0.9.5372/datomic-free-0.9.5372.pom
...

如果希望在Intellij里面跑GettingStarted的code,pom.xml里面添加:

1
2
3
4
5
<dependency>
<groupId>com.datomic</groupId>
<artifactId>datomic-free</artifactId>
<version>0.9.5372</version>
</dependency>

示例解析

运行示例

运行Java示例代码:

1
2
3
4
cd ~/datomic-free-0.9.5372
ls samples/seattle/GettingStarted.java
javac -Xlint:unchecked -cp `bin/classpath` samples/seattle/GettingStarted.java
java -cp `bin/classpath`:samples/seattle GettingStarted

第一步理解数据模型,这样就对这个产品有一个感性的认识了。
datomic提到的一个很重要的点是不会原地更新,这样可以获取所有数据的完整轨迹。

schema定义

schema(seattle-schema.edn)的定义:
community依赖了neighborhood,neighborhood依赖了district

1
2
3
4
5
6
{:db/id #db/id[:db.part/db]
:db/ident :community/neighborhood
:db/valueType :db.type/ref
:db/cardinality :db.cardinality/one
:db/doc "A community's neighborhood"
:db.install/_attribute :db.part/db}

以下这些字段是枚举类型

1
2
3
:community.orgtype
:community.type
:region

定义类似于:

1
2
3
4
[:db/add #db/id[:db.part/user] :db/ident :community.orgtype/community]
[:db/add #db/id[:db.part/user] :db/ident :community.orgtype/commercial]
[:db/add #db/id[:db.part/user] :db/ident :community.orgtype/nonprofit]
[:db/add #db/id[:db.part/user] :db/ident :community.orgtype/personal]

数据说明

测试数据(seattle-data0.edn)的定义:

每三条是定义一条完整的记录,依次是定义district/neighborhood/community

1
2
3
4
5
{:district/region :region/e, :db/id #db/id[:db.part/user -1000001], :district/name "East"}
{:db/id #db/id[:db.part/user -1000002], :neighborhood/name "Capitol Hill", :neighborhood/district #db/id[:db.part/user -1000001]}
{:community/category ["15th avenue residents"], :community/orgtype :community.orgtype/community, :community/type :community.type/email-list, :db/id #db/id[:db.part/user -1000003], :community/name "15th Ave Community", :community/url "http://groups.yahoo.com/group/15thAve_Community/", :community/neighborhood #db/id[:db.part/user -1000002]}

这个数据模型和mysql不一样。在mysql里面,district/neighborhood/community会定义成3张表,建立外键。

query含义

query的用法比较难以理解,比较靠近clojure的语法。
比如sample里面的第一条query:

1
[:find ?c :where [?c :community/name]]

还有后面的:

1
2
[:find [?n ...] :where [_ :community/name ?n]]
[:find ?n (pull ?c [:community/url]) :where [?c :community/name ?n]]

弄懂query的语法,形成形象的认识,就我的惯用方法而言,得用interactive的模式去多试验。
当然,仔细读懂文档是更直接更快的办法。

获取community的所有数据

1
2
3
4
5
6
7
8
9
10
11
12
user=> (def pull-results (q '[:find (pull ?c [*]) :where [?c :community/name]] (db conn)))
#'user/pull-results
user=> (pprint (first pull-results))
[{:db/id 17592186045443,
:community/name "Admiral Neighborhood Association",
:community/url "http://groups.yahoo.com/group/AdmiralNeighborhood/",
:community/neighborhood {:db/id 17592186045442},
:community/category ["neighborhood association"],
:community/orgtype {:db/id 17592186045417},
:community/type [{:db/id 17592186045421}]}]
nil

获取community的name/category两列的数据

1
2
3
4
5
6
7
user=> (def pull-results (q '[:find (pull ?c [:community/name :community/category]) :where [?c :community/name]] (db conn)))
#'user/pull-results
user=> (pprint (first pull-results))
[{:community/name "Admiral Neighborhood Association",
:community/category ["neighborhood association"]}]
nil

获取community的所有name

1
2
3
4
5
user=> (def results (q '[:find [?n ...] :where [_ :community/name ?n]] (db conn)))
#'user/results
user=> (pprint results)
["Admiral Neighborhood Association" "15th Ave Community"]

获取community的所有name和url

1
2
3
4
5
6
7
8
9
10
user=> (pprint (seq (q '[:find ?n (pull ?c [:community/url])
:where
[?c :community/name ?n]]
(db conn))))
(["Admiral Neighborhood Association"
{:community/url
"http://groups.yahoo.com/group/AdmiralNeighborhood/"}]
["15th Ave Community"
{:community/url "http://groups.yahoo.com/group/15thAve_Community/"}])
nil

运行Transactor

1
2
cd ~/datomic-free-0.9.5372
./bin/transactor config/samples/free-transactor-template.properties

使用的protocol是free,免费版无法使用其它的transactor类型

1
2
3
4
5
6
Critical failure, cannot continue: Error starting transactor
java.lang.IllegalArgumentException: :db.error/missing-transactor-property 'license-key' property not set, required for protocol: dev in config/samples/free-transactor-template.properties
at datomic.error$arg.invokeStatic(error.clj:57)
at datomic.error$arg.invoke(error.clj:52)
at datomic.error$arg.invokeStatic(error.clj:55)
at datomic.error$arg.invoke(error.clj:52)

datomic提供的transactor类型:

Storage Where Purpose
mem Your process, no durability Experimenting, testing
dev Process on local machine, with storage Development
cass Cassandra cluster Production
couchbase Couchbase database Production
sql SQL database Production
riak Riak cluster Production
inf Infinispan memory cluster Production
ddb Amazon Dynamo DB table Production

总结

到现在为止,只是跑通datomic的例子,并没有理解到datomic的精髓

参考文献

[1] http://www.infoq.com/cn/articles/Datomic-Information-Model
[2] http://www.infoq.com/cn/articles/Architecture-Datomic
[3] http://www.datomic.com/