erlang mnesia数据库事物应用

mneia数据库时erlang自带的一个nosql数据库,对其读、写、删除操作均有脏读和非脏读两种,之前存在一个误区就是脏读和非脏读操作都支持transaction,在进行代码测试的时候出现和事物特性不一致的情况。

问题背景描述:

项目投产后,日常运行中会产生大量的数据,当数据量不断增加,所占的内存空间就会越大,对读写操作效率会有影响,而对于几个月前的数据项目实际的运行中基本用不到,但又不能将其直接删除,考虑将其迁移到一个备份表中,并将主表中的数据将其删除。考虑到数据的安全性:将备份表的写操作和主表的删除操作,放入到事物中,要么都成功,要么都是失败。同时为了保证项目性能,减少备份的时候,对数据库的压力,在进行读写、删除的时候采用diry的方式,在测试的时候发现,dirty操作,虽然加入到了事物,但是并不具事物的特性:同时成功同时失败。

测试代码

-module(test_mnesia).
-import(lists, [foreach/2]).
-include_lib("stdlib/include/qlc.hrl").
-compile(export_all).
-record(shop, {item, quantity, cost}).

do_this_once() ->
  mnesia:create_schema([node()]),
  mnesia:start(),
  mnesia:create_table(shop, [{attributes, record_info(fields, shop)}]),
  mnesia:stop().

start() ->
  mnesia:stop(),
  mnesia:start(),
  mnesia:wait_for_tables([shop], 2000),
  init_table(shop_info()).

get_all(TabelName) ->
  Qh =qlc:q([X || X <- mnesia:table(TabelName)]),
  F = fun() -> qlc:e(Qh) end,
  {atomic, Val} = mnesia:transaction(F),
  Val.

shop_info() ->
  [%% The shop table
    {shop, apple, 20, 2.3},
    {shop, orange, 100, 3.8},
    {shop, pear, 200, 3.6},
    {shop, banana, 420, 4.5}
  ].
init_table(TableData) ->
  F = fun(Model) -> mnesia:dirty_write(Model) end,
  lists:foreach(F, TableData).

delete(Item) ->
  Oid = {shop, Item},
  F = fun() ->
    mnesia:delete(Oid)
      end,
  mnesia:transaction(F).

dirty_delete(Item) ->
  Oid = {shop, Item},
  F = fun() ->
    mnesia:dirty_delete(Oid)
      end,
  mnesia:transaction(F).

write() ->
  Oid =  {shop, potato, 2456, 1.2},
  F = fun() ->
    mnesia:write(Oid)
      end,
  mnesia:transaction(F).

dirty_write() ->
  Oid =  {shop, potato, 2456, 1.2},
  F = fun() ->
    mnesia:dirty_write(Oid)
      end,
  mnesia:transaction(F).

execute(Function,Pram) when is_function(Function),is_list(Pram) ->
  F = fun() ->
    apply(Function,Pram)
    ,true = ok  %在事物里制造问题,验证事物的有效性
      end,
  mnesia:transaction(F).
验证测试流程
  • 初始化操作
1> c(test_mnesia).
test_mnesia.erl:67: Warning: no clause will ever match
{ok,test_mnesia}
2> test_mnesia:do_this_once().
stopped
3>
=INFO REPORT==== 28-Sep-2017::18:19:14 ===
    application: mnesia
    exited: stopped
    type: temporary

3> test_mnesia:start().
ok
4>
  • delete测试流程:最总无法删除数据里的数据
6>  test_mnesia:get_all(shop).                                               
[{shop,apple,20,2.3},                                                        
 {shop,orange,100,3.8},                                                      
 {shop,pear,200,3.6},                                                        
 {shop,banana,420,4.5}]                                                      
7> test_mnesia:execute(fun test_mnesia:delete/1,[apple]).                    
{aborted,{{badmatch,ok},                                                     
          [{test_mnesia,'-execute/2-fun-0-',2,                               
                        [{file,"test_mnesia.erl"},{line,67}]},               
           {mnesia_tm,apply_fun,3,[{file,"mnesia_tm.erl"},{line,836}]},      
           {mnesia_tm,execute_transaction,5,                                 
                      [{file,"mnesia_tm.erl"},{line,811}]},                  
           {erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,674}]},         
           {shell,exprs,7,[{file,"shell.erl"},{line,686}]},                  
           {shell,eval_exprs,7,[{file,"shell.erl"},{line,641}]},             
           {shell,eval_loop,3,[{file,"shell.erl"},{line,626}]}]}}            
8> test_mnesia:get_all(shop).                                                
[{shop,apple,20,2.3},                                                        
 {shop,orange,100,3.8},                                                      
 {shop,pear,200,3.6},                                                        
 {shop,banana,420,4.5}]                                                      
  • dirty_delete测试流程:apple的记录将会被删除
8> test_mnesia:get_all(shop).
[{shop,apple,20,2.3},
 {shop,orange,100,3.8},
 {shop,pear,200,3.6},
 {shop,banana,420,4.5}]
9> test_mnesia:execute(fun test_mnesia:dirty_delete/1,[apple]).
{aborted,{{badmatch,ok},
          [{test_mnesia,'-execute/2-fun-0-',2,
                        [{file,"test_mnesia.erl"},{line,67}]},
           {mnesia_tm,apply_fun,3,[{file,"mnesia_tm.erl"},{line,836}]},
           {mnesia_tm,execute_transaction,5,
                      [{file,"mnesia_tm.erl"},{line,811}]},
           {erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,674}]},
           {shell,exprs,7,[{file,"shell.erl"},{line,686}]},
           {shell,eval_exprs,7,[{file,"shell.erl"},{line,641}]},
           {shell,eval_loop,3,[{file,"shell.erl"},{line,626}]}]}}
10> test_mnesia:get_all(shop).
[{shop,orange,100,3.8},
 {shop,pear,200,3.6},
 {shop,banana,420,4.5}]
  • write测试流程:{shop, potato, 2456, 1.2}不能写入数据库
10> test_mnesia:get_all(shop).                                                         
[{shop,orange,100,3.8},                                                                
 {shop,pear,200,3.6},                                                                  
 {shop,banana,420,4.5}]                                                                
11> test_mnesia:execute(fun test_mnesia:write/0,[]).                                   
{aborted,{{badmatch,ok},                                                               
          [{test_mnesia,'-execute/2-fun-0-',2,                                         
                        [{file,"test_mnesia.erl"},{line,67}]},                         
           {mnesia_tm,apply_fun,3,[{file,"mnesia_tm.erl"},{line,836}]},                
           {mnesia_tm,execute_transaction,5,                                           
                      [{file,"mnesia_tm.erl"},{line,811}]},                            
           {erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,674}]},                   
           {shell,exprs,7,[{file,"shell.erl"},{line,686}]},                            
           {shell,eval_exprs,7,[{file,"shell.erl"},{line,641}]},                       
           {shell,eval_loop,3,[{file,"shell.erl"},{line,626}]}]}}                      
12>  test_mnesia:get_all(shop).                                                        
[{shop,orange,100,3.8},                                                                
 {shop,pear,200,3.6},                                                                  
 {shop,banana,420,4.5}]                                                                
  • dirty_write测试流程:{shop, potato, 2456, 1.2}可以写入数据库
12>  test_mnesia:get_all(shop).
[{shop,orange,100,3.8},
 {shop,pear,200,3.6},
 {shop,banana,420,4.5}]
13> test_mnesia:execute(fun test_mnesia:dirty_write/0,[]).
{aborted,{{badmatch,ok},
          [{test_mnesia,'-execute/2-fun-0-',2,
                        [{file,"test_mnesia.erl"},{line,67}]},
           {mnesia_tm,apply_fun,3,[{file,"mnesia_tm.erl"},{line,836}]},
           {mnesia_tm,execute_transaction,5,
                      [{file,"mnesia_tm.erl"},{line,811}]},
           {erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,674}]},
           {shell,exprs,7,[{file,"shell.erl"},{line,686}]},
           {shell,eval_exprs,7,[{file,"shell.erl"},{line,641}]},
           {shell,eval_loop,3,[{file,"shell.erl"},{line,626}]}]}}
14>  test_mnesia:get_all(shop).
[{shop,potato,2456,1.2},
 {shop,orange,100,3.8},
 {shop,pear,200,3.6},
 {shop,banana,420,4.5}]

总结:从上面的测试可以看出,mnesia数据库关于dirty的操作不支持事物。

你可能感兴趣的:(erlang mnesia数据库事物应用)