Mnesia: Erlang数据库(二)(学习笔记)

test mnesia.erl 

-modu1e(test_mnesia).
-import(lists, [foreach/2]).
-compile(export_all).
 
-include_lib("stdlib/include/qlc.hrl").
-record(shop, {item, quantity, cost}).
-record(cost, {name, price}).
-record(design, {id, plan}).
do_this_once() ->
  mnesia:create_schema([node()]),
  mnesia:start(),
  mnesia:create_table(shop, [{attributes, record_info(fields, shop)}]),
  mnesia:create_table(cost, [{attributes, record_info(fields, cost)}]),
  mnesia:create_table(design, [{attributes, record_info(fields, design)}]),
  mnesia:stop().
 
start() ->
  mnesia:start(),
  mnesia:wait_for_tables([shop, cost, design], 20000).
 
demo(select_shop) -> do(qlc:q([X || X <- mnesia:table(shop)]));
 
demo(select_some) -> do(qlc:q([{X#shop.item, X#shop.quantity} || X <- mnesia:table(shop)]));
 
demo(reorder) -> do(qlc:q([X#shop.item || X <- mnesia:table(shop), X#shop.quantity < 250]));
 
 
demo(join) -> do(qlc:q([X#shop.item || X <- mnesia:table(shop),
  X#shop.quantity < 250,
  Y <- mnesia:table(cost),
  X#shop.item =:= Y#cost.name,
  Y#cost.price < 2])).
do(Q) ->
  F = fun() -> qlc:e(Q) end,
  {atomic, Val} = mnesia:transaction(F),
  Val.
 
example_tables() ->
  [{shop, apple, 20, 2.3},
    {shop, orange, 100, 3.8},
    {shop, pear, 200, 3.6},
    {shop, banana, 420, 4.5},
    {shop, potato, 2456, 1.2},
 
    {cost, apple, 1.5},
    {cost, orange, 2.4},
    {cost, pear, 2.2},
    {cost, banana, 1.5},
    {cost, potato, 0.6}].
 
add_shop_item(Name, Quantity, Cost) ->
  Row = #shop{item = Name, quantity = Quantity, cost = Cost},
  F = fun() ->
    mnesia:write(Row)
      end,
  mnesia:transaction(F).
 
remove_shop_item(Item) ->
  Oid = {shop, Item},
  F = fun() ->
    mnesia:delete(Oid)
      end,
  mnesia:transaction(F).
 
farmer(Nwant) ->
  F = fun() ->
    [Apple] = mnesia:read({shop, apple}),
    Napples = Apple#shop.quantity,
    Apple1 = Apple#shop{quantity = Napples + 2 * Nwant},
    mnesia:write(Apple1),
    [Orange] = mnesia:read({shop, orange}),
    NOranges = Orange#shop.quantity,
    if
      NOranges >= Nwant ->
        N1 = NOranges - Nwant,
        Orange1 = Orange#shop{quantity = N1},
        mnesia:write(Orange1);
      true ->
        mnesia:abort(oranges)
    end
      end,
  mnesia:transaction(F).
 
reset_tables() ->
  mnesia:clear_table(shop),
  mnesia:clear_table(cost),
  F = fun() ->
    foreach(fun mnesia:write/1, example_tables())
      end,
  mnesia:transaction(F).
 
add_plans() ->
  D1 = #design{id = {joe, 1},
    plan = {circle, 10}},
  D2 = #design{id = fred,
    plan = {rectangle, 10, 5}},
  D3 = #design{id = {jane, {house, 23}},
    plan = {house,
      [{floor, 1, [{doors, 3},
        {windows, 12},
        {rooms, 5}]},
        {floor, 2,
          [{doors, 2},
            {rooms, 4},
            {windows, 15}]}]}},
  F = fun() ->
    mnesia:write(D1),
    mnesia:write(D2),
    mnesia:write(D3)
      end,
  mnesia:transaction(F).
 
get_plan(PlanId) ->
  F = fun() -> mnesia:read({design, PlanId}) end,
  mnesia:transaction(F).

加载测试数据

test_mnesia:example_tables/0函数用来初始化数据表,填充测试数据。

example_tables() ->
  [{shop, apple, 20, 2.3},
    {shop, orange, 100, 3.8},
    {shop, pear, 200, 3.6},
    {shop, banana, 420, 4.5},
    {shop, potato, 2456, 1.2},
 
    {cost, apple, 1.5},
    {cost, orange, 2.4},
    {cost, pear, 2.2},
    {cost, banana, 1.5},
    {cost, potato, 0.6}].
 

向Mnesia插入数据的代码 

reset_tables() ->
  mnesia:clear_table(shop),
  mnesia:clear_table(cost),
  F = fun() ->
    foreach(fun mnesia:write/1, example_tables())
      end,
  mnesia:transaction(F).

实际上,通过example_tables/1函数返回的列表,只是对其中的每一个元组调用mnesia:write。

do()函数

do(Q) ->
  F = fun() -> qlc:e(Q) end,
  {atomic, Val} = mnesia:transaction(F),
  Val.

它是在Mnesia的事务中调用qlc:e(Q)。Q是一个编译过的QLC查询,qlc:e(Q)执行这个查询,并将查询结果都返回到一个列表之中。返回值{atomic, Val}的意思是事务成功,返回值是val。这里的Val是交易的执行结果。

在表中保存复杂数据

 Mnesia是被设计用来保存Erlang数据结构的。更明确地说,你可以把任意类型的Erlang数据结构保存到Mnesia表中。
比如说,我们要把一些建筑的设计方案放到Mnesia的数据库中。首先,我们需要一个记录,用来表示这些设计:

-record(design, {id, plan}).

向数据库中添加一些设计

add_plans() ->
  D1 = #design{id = {joe, 1},
    plan = {circle, 10}},
  D2 = #design{id = fred,
    plan = {rectangle, 10, 5}},
  D3 = #design{id = {jane, {house, 23}},
    plan = {house,
      [{floor, 1, [{doors, 3},
        {windows, 12},
        {rooms, 5}]},
        {floor, 2,
          [{doors, 2},
            {rooms, 4},
            {windows, 15}]}]}},
  F = fun() ->
    mnesia:write(D1),
    mnesia:write(D2),
    mnesia:write(D3)
      end,
  mnesia:transaction(F).

 向数据库添加一些设计

1>test mnesia:start().
ok
2>test_mnesia:add _plans().
{atomic,ok}

 访问函数来获取这些设计

get_plan(PlanId) ->
  F = fun() -> mnesia:read({design, PlanId}) end,
  mnesia:transaction(F).
3> test_mnesia:get_plan(fred).
{atomic, [{design, fred, {rectangle, 10, 5}}]}
4 >test_mnesia:get_plan(jane, {house, 23}}).
{atomic, [{design, {jane, {house, 23}},
          {house, [{floor, 1, [{doors, 3},
                          {windows, 12},
                          {rooms,5]]},
                   {floor, 2,[{doors, 2},
                          {rooms,4},
                          {windows, 15}]3]}}]}

数据库中的数据结构与编程语言的数据结构之间并不存在“匹配阻抗”问题。这意味着向数据库增加或者删除复杂的数据结构是非常迅速的。

表的类型和位置 

        Mnesia数据表可以进行很多种不同的配置。首先我们可以选择将表存储在内存或者磁盘上(或者同时保存在内存和磁盘上),其次,可以选择将数据表保存在一台机器上,或者在多台机器上备份。
        在设计阶段,我们就必须要认真思考我们想要存储的数据有什么样的特性,然后根据这些特
 性来选择。下面是Mnesia数据表的属性。

内存表

非常快,但其中数据是瞬态的,所以当系统崩溃或者停掉数据库的时候,这些数据都会丢失。

磁盘表

 系统崩溃不会导致其中的数据丢失

创建表

 创建一个表的时候,我们调用mnesia:create_table(Name,Args)函数。这里的Args是由{Key,Val}这样的元组组成的列表。如果表创建成功,会得到{atomic,ok}返回值,否则会返回{aborted,Reason}。

下面是最常见的create_table参数。

Name
这是表的名字(一个原子)。通常来说它的取值就是Erlang记录的名字,这个记录就是我们之前提到过的表示每行数据的记录。
{type,Type}
这个参数表明表的类型。Type是set、ordered_set或者bag。其意义与我们在15.2节中提到的一样。
{disc_copies,NodeList}
NodeList是Erlang节点的列表,这个表的备份会存储在这些节点上。使用这个选项时,系统会同时创建内存表和磁盘表。
一个节点上有一个disc_copies类型的备份表,同时另一个节点上可能有以不同类型存储的同一个表。这个配置提供了如下梦幻般的特性。

(1)读操作在内存中执行,速度飞快。

(2)写操作时,数据被写到持久介质上。

{ram_copies,NodeList}
NodeList中的每个Erlang节点上都会有这个表的内存备份。

{disc_only_copies,NodeList}
NodeList中的每个Erlang节点上都会有一个这个表的磁盘备份。因为这个表不是在内存中的,所以,访问起来会慢一些。
fattributes,AtomList}
AtomList的列表表明了表中每列的名称。需要留意的是,当我们为此建立了xxx这样的Erlang记录时,我们可以简单的使用这样的语法{attribute,record_info(fields,xxx)},而不需要显式的逐个字段的指定列名。

表属性的常见组合

下面是一些常见的选项配置,覆盖了我们经常会用的各种情况

mnesia:createtable(shop,[Attrs])

只在一个节点的内存中存储。

如果这个节点失效,表中的数据都会丢失。

在所有的方法中,这是最快的组合。

机器的物理内存要能放下整张表。

mnesia:create_table(shop,[Attrs,{disc_copies,[node()]}])

在一个节点上做内存+磁盘备份。

如果节点失效,表中的数据可以从磁盘上恢复。

读操作很快,写操作稍慢。 

机器的物理内存要能放下整张表。

mnesia:create_table(shop,[Attrs,{disc_only_copies,[node()]}]

单个节点的磁盘备份。

无须考虑内存大小,可以存储大量数据。

比用内存备份的方式要慢一些。

mnesia:create_table(shop,[Attrs,iram_copies,[node() , someOtherNode()]})

 这个表在两个节点上有内存备份。

如果两个节点都失效了,数据会丢失。

机器的物理内存要能放下整张表。

在两个节点上都能访问这个表。

mnesia:create_table(shop,[Attrs,{disc_copies,[node() , someOtherNode()]}])

两个节点上都做磁盘备份。

每个节点上都可以进行恢复。

两个节点都失效,仍然可以恢复。

表的行为

当一个表在多个Erlang节点上备份时,它会尽可能的进行同步。如果某个节点失效,系统会继续保持运作,但是少了一个备份。当失效的节点再次上线时,它会与其他节点再次进行同步,备份数量得以保持。
 

  • 17
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值