yb_lin

导航

Mnesia 学习笔记

2、Mnesia 入门

一个演示用的数据库例子。这个例子以后还会用到,也会做些修改。

首先要做以下事情:

● 启动Erlang会话,指定Mnesia数据库的位置

● 初始化数据库结构

● 启动Mnesia,创建所需数据表格

2.1 第一次启动 Mnesia

打开DOS命令控制台窗口,执行这句:

D:\Program Files\erl5.6.5\bin > erl -mnesia dir '"d:/erlang/learn/db/"'

进入Erlang的shell,执行语句:

Eshell V5.6.5  (abort with ^G)

1> mnesia:create_schema([node()]).

这时,你可看到,在路径 d:/erlang/learn/ 下新增子目录 db 

并且,db 中有一文件 FALLBACK.BUP

2> mnesia:start().

ok

3> mnesia:create_table(funky, []).

{atomic,ok}

4> mnesia:info().

---> Processes holding locks <---

---> Processes waiting for locks <---

---> Participant transactions <---

---> Coordinator transactions <---

---> Uncertain transactions <---

---> Active tables <---

funky          : with 0        records occupying 279      words of mem

schema         : with 2        records occupying 499      words of mem

===> System info in version "4.4.7", debug level = none <===

opt_disc. Directory "d:/erlang/learn/db" is used.

use fallback at restart = false

running db nodes   = [nonode@nohost]

stopped db nodes   = []

master node tables = []

remote             = []

ram_copies         = [funky]

disc_copies        = [schema]

disc_only_copies   = []

[{nonode@nohost,disc_copies}] = [schema]

[{nonode@nohost,ram_copies}] = [funky]

3 transactions committed, 0 aborted, 0 restarted, 1 logged to disc

0 held locks, 0 in queue; 0 local transactions, 0 remote

0 transactions waits for other nodes: []

ok

5>

2.2 “导盲”示例

这个例子是为你、我、他这些Mnesia“盲”预备的。:-)

Mnesia 数据库由一组表格构成。每个表格的数据成员是Erlang的记录(record)。表格还有些属性,譬如位置和存期(persistence)。

本例的任务是:

● 启动 Erlang 系统,指定数据库所处位置;

● 对数据库进行初始化,将数据库操作涉及的节点,登记备案;

● 启动 Mnesia。

● 创建并填写表格。

2.2.1 数据库例子

数据库模型如下:

● 三个实体:员工employee,项目project,部门department。

● 实体之间有三种关系:

(1)部门由员工管理,形成manager关系;

(2)员工在部门中工作,形成at_dep关系;

(3)员工都在为项目工作形成in_proj关系。

2.2.2 定义结构和内容

首先在文本文件company.hrl中定义记录,形成我们数据库的简单结构:

-record(employee, {emp_no,

                   name,

                   salary,

                   sex,

                   phone,

                   room_no}).

-record(dept, {id, 

               name}).

-record(project, {name,

                  number}).

-record(manager, {emp,

                  dept}).

-record(at_dep, {emp,

                 dept_id}).

-record(in_proj, {emp,

                  proj_name}).

2.2.3 应用程序

%% company.erl

-module(company).

-include_lib("stdlib/include/qlc.hrl").

-include("d:/erlang/learn/db/company.hrl").

-export([init/0]).

init() ->

    mnesia:create_table(employee,

                        [{attributes, record_info(fields, employee)}]),

    mnesia:create_table(dept,

                        [{attributes, record_info(fields, dept)}]),

    mnesia:create_table(project,

                        [{attributes, record_info(fields, project)}]),

    mnesia:create_table(manager, [{type, bag}, 

                                  {attributes, record_info(fields, manager)}]),

    mnesia:create_table(at_dep,

                         [{attributes, record_info(fields, at_dep)}]),

    mnesia:create_table(in_proj, [{type, bag}, 

                                  {attributes, record_info(fields, in_proj)}]).

大致重复上例过程:

D:\Program Files\erl5.6.5\bin>erl -mnesia dir '"d:/erlang/learn/db/Mnesia.Company"'

Eshell V5.6.5  (abort with ^G)

1> mnesia:create_schema([node()]).

ok

2> mnesia:start().

ok

3> c("d:/erlang/learn/db/company").

{ok,company}

4> company:init().

{atomic,ok}

4> mnesia:info().

---> Processes holding locks <---

---> Processes waiting for locks <---

---> Participant transactions <---

---> Coordinator transactions <---

---> Uncertain transactions <---

---> Active tables <---

in_proj        : with 0        records occupying 279      words of mem

at_dep         : with 0        records occupying 279      words of mem

manager        : with 0        records occupying 279      words of mem

project        : with 0        records occupying 279      words of mem

dept           : with 0        records occupying 279      words of mem

employee       : with 0        records occupying 279      words of mem

schema         : with 7        records occupying 1057     words of mem

===> System info in version "4.4.7", debug level = none <===

opt_disc. Directory "d:/erlang/learn/db/Mnesia.Company" is used.

use fallback at restart = false

running db nodes   = [nonode@nohost]

stopped db nodes   = []

master node tables = []

remote             = []

ram_copies         = [at_dep,dept,employee,in_proj,manager,project]

disc_copies        = [schema]

disc_only_copies   = []

[{nonode@nohost,disc_copies}] = [schema]

[{nonode@nohost,ram_copies}] = [employee,dept,project,manager,at_dep,in_proj]

8 transactions committed, 0 aborted, 0 restarted, 6 logged to disc

0 held locks, 0 in queue; 0 local transactions, 0 remote

0 transactions waits for other nodes: []

ok

5>

创建了一组表格:

mnesia:create_table(Name,ArgList). 

参数 ArgList 的具体取值以后会讲。

要写个函数,把员工记录插入数据库中,就必须有个at_dep记录和一组in_proj记录。下面的代码完成此事:

insert_emp(Emp, DeptId, ProjNames) ->

    Ename = Emp#employee.name,

    Fun = fun() ->

                  mnesia:write(Emp),

                  AtDep = #at_dep{emp = Ename, dept_id = DeptId},

                  mnesia:write(AtDep),

                  mk_projs(Ename, ProjNames)

          end,

    mnesia:transaction(Fun).

mk_projs(Ename, [ProjName|Tail]) ->

    mnesia:write(#in_proj{emp = Ename, proj_name = ProjName}),

    mk_projs(Ename, Tail);

mk_projs(_, []) -> ok.

这个函数可以这样用:

          Emp  = #employee{emp_no= 104732,

                           name = klacke,

                           salary = 7,

                           sex = male,

                           phone = 98108,

                           room_no = {221, 015}},

        insert_emp(Me, 'B/SFR', [Erlang, mnesia, otp]).

 

2.2.6 向数据库增加记录和关系

向数据库Company追加记录的结果是:

Employees 

        {employee, 104465, "Johnson Torbjorn",   1, male,  99184, {242,038}}.

        {employee, 107912, "Carlsson Tuula",     2, female,94556, {242,056}}.

        {employee, 114872, "Dacker Bjarne",      3, male,  99415, {221,035}}.

        {employee, 104531, "Nilsson Hans",       3, male,  99495, {222,026}}.

        {employee, 104659, "Tornkvist Torbjorn", 2, male,  99514, {222,022}}.

        {employee, 104732, "Wikstrom Claes",     2, male,  99586, {221,015}}.

        {employee, 117716, "Fedoriw Anna",       1, female,99143, {221,031}}.

        {employee, 115018, "Mattsson Hakan",     3, male,  99251, {203,348}}.

Dept 

        {dept, 'B/SF',  "Open Telecom Platform"}.

        {dept, 'B/SFP', "OTP - Product Development"}.

        {dept, 'B/SFR', "Computer Science Laboratory"}.

Projects 

        %% projects

        {project, erlang, 1}.

        {project, otp, 2}.

        {project, beam, 3}.

        {project, mnesia, 5}.

        {project, wolf, 6}.

        {project, documentation, 7}.

        {project, www, 8}.

上面的表格是真实的记录,下面的是建立关系的。

Manager 

        {manager, 104465, 'B/SF'}.

        {manager, 104465, 'B/SFP'}.

        {manager, 114872, 'B/SFR'}.

At_dep 

        {at_dep, 104465, 'B/SF'}.

        {at_dep, 107912, 'B/SF'}.

        {at_dep, 114872, 'B/SFR'}.

        {at_dep, 104531, 'B/SFR'}.

        {at_dep, 104659, 'B/SFR'}.

        {at_dep, 104732, 'B/SFR'}.

        {at_dep, 117716, 'B/SFP'}.

        {at_dep, 115018, 'B/SFP'}.

In_proj 

        {in_proj, 104465, otp}.

        {in_proj, 107912, otp}.

        {in_proj, 114872, otp}.

        {in_proj, 104531, otp}.

        {in_proj, 104531, mnesia}.

        {in_proj, 104545, wolf}.

        {in_proj, 104659, otp}.

        {in_proj, 104659, wolf}.

        {in_proj, 104732, otp}.

        {in_proj, 104732, mnesia}.

        {in_proj, 104732, erlang}.

        {in_proj, 117716, otp}.

        {in_proj, 117716, documentation}.

        {in_proj, 115018, otp}.

        {in_proj, 115018, mnesia}.

数据库Company现在有了初始化数据。 

2.2.7 写查询语句

从DBMS检索数据,通常应当使用函数 mnesia:read/3 或 mnesia:read/1。下面的函数是关于“增加工资”的:

raise(Eno, Raise) ->

    F = fun() ->

                [E] = mnesia:read(employee, Eno, write),

                Salary = E#employee.salary + Raise,

                New = E#employee{salary = Salary},

                mnesia:write(New)

        end,

    mnesia:transaction(F).

进行数据库查询,有2个办法:

● Mnesia functions 

● QLC 

2.2.7.1 Mnesia 函数

mnesia:select(employee, [{#employee{sex = female, name = '$1', _ = '_'},[], ['$1']}]).

all_females() ->

    F = fun() ->

                Female = #employee{sex = female, name = '$1', _ = '_'},

                mnesia:select(employee, [{Female, [], ['$1']}])

        end,

    mnesia:transaction(F).

在Erlang shell中的操作:

(klacke@gin)1> company:all_females().

{atomic,  ["Carlsson Tuula", "Fedoriw Anna"]}

2.2.7.2 使用 QLC 

使用QLC很费事,不如用Mnesia函数来得直白,但QLC的语法美观。

从数据库中选出女员工的集合:

Q = qlc:q([E#employee.name || E <- mnesia:table(employee),

                      E#employee.sex == female]),

qlc:e(Q),

用QLC表元选择功能必须在事务中进行:

females() ->

    F = fun() ->

                Q = qlc:q([E#employee.name || E <- mnesia:table(employee),

                                              E#employee.sex == female]),

                qlc:e(Q)

        end,

    mnesia:transaction(F).

下面是结果相同的shell调用函数:

(klacke@gin)1> company:females().

{atomic, ["Carlsson Tuula", "Fedoriw Anna"]}

It is possible to combine list comprehensions with low level Mnesia functions in the same transaction. If we want to raise the salary of all female employees we execute: 

可以把表元选择的操作,与Mnesia低层函数调用,结合在同一事务里。

如提高全体女员工的工资:

raise_females(Amount) ->

    F = fun() ->

                Q = qlc:q([E || E <- mnesia:table(employee),

                                E#employee.sex == female]),

                Fs = qlc:e(Q),

                over_write(Fs, Amount)

        end,

    mnesia:transaction(F).

over_write([E|Tail], Amount) ->

    Salary = E#employee.salary + Amount,

    New = E#employee{salary = Salary},

    mnesia:write(New),

    1 + over_write(Tail, Amount);

over_write([], _) ->

    0.

posted on 2009-09-26 16:56  废铁  阅读(1093)  评论(0编辑  收藏  举报