数据的Erlang进程没有从隔离性中得到好处 脏操作的优点是它们比相应的事务处理快的多
如果脏操作处理disc_copies、disc_only_copies类型的表,则写到磁盘 如果脏写操作执行在这种表上,Mnesia也保证所有的表备份一起更新
脏操作将保证某种级别的一致性,例如脏操作不可能返回混乱的record,这样每个单独的读或写操作以一个原子的行为执行
所有的脏操作在失败时调用exit({aborted, Reason}),即使在事务中执行以下方法也不会获取锁:
Java代码
?? mnesia:dirty_read({Tab, Key}) ?? mnesia:dirty_write(Record) ?? mnesia:dirty_delete({Tab, Key}) ?? mnesia:dirty_delete_object(Record) ?? mnesia:dirty_first(Tab) ?? mnesia:dirty_next(Tab, Key) ?? mnesia:dirty_last(Tab) ?? mnesia:dirty_prev(Tab, Key) ?? mnesia:dirty_slot(Tab, Slot)
?? mnesia:dirty_update_counter({Tab, Key}, Val) ?? mnesia:dirty_match_object(Pat) ?? mnesia:dirty_select(Tab, Pat)
?? mnesia:dirty_index_match_oject(Pat, Pos) ?? mnesia:dirty_index_read(Tab, SecondaryKey, Pos) ?? mnesia:dirty_all_keys(Tab)
mnesia:dirty_read({Tab, Key}) mnesia:dirty_write(Record) mnesia:dirty_delete({Tab, Key}) mnesia:dirty_delete_object(Record) mnesia:dirty_first(Tab) mnesia:dirty_next(Tab, Key) mnesia:dirty_last(Tab) mnesia:dirty_prev(Tab, Key) mnesia:dirty_slot(Tab, Slot)
mnesia:dirty_update_counter({Tab, Key}, Val) mnesia:dirty_match_object(Pat) mnesia:dirty_select(Tab, Pat)
mnesia:dirty_index_match_oject(Pat, Pos) mnesia:dirty_index_read(Tab, SecondaryKey, Pos) mnesia:dirty_all_keys(Tab)
4,Record名与Table名
Mnesia里表的所有record必须有一样的名字,所有的record必须为相同record类型的实例 但是record名没有必要和table名一样
如果表创建时没有指定record_name属性,那么表里所有的record会有和表名一样的record名 如果多个表创建时指定了相同的record_name属性,那么相同名字的record可以存储在多个表中 访问这些指定了record_name的表时不能简单的使用mnesia:write/1和mnesia:s_write/1,而应该使用mnesia:write/3:
Java代码
?? mnesia:write(subscriber, #subscriber{}, write)
?? mnesia:write(my_subscriber, #subscriber{}, sticky_write) ?? mnesia:write(your_subscriber, #subscriber{}, write)
mnesia:write(subscriber, #subscriber{}, write)
mnesia:write(my_subscriber, #subscriber{}, sticky_write) mnesia:write(your_subscriber, #subscriber{}, write)
5,Activity概念和多种访问上下文
前面说到,mnesia:transaction/1,2,3的参数functional object(Fun)执行以下表操作:
Java代码
?? mnesia:write/3 (write/1, s write/1) ?? mnesia:delete/3 (delete/1, s delete/1)
?? mnesia:delete object/3 (delete object/1, s delete object/1) ?? mnesia:read/3 (read/1, wread/1) ?? mnesia:match object/2 (match object/1) ?? mnesia:select/3 (select/2)
?? mnesia:foldl/3 (foldl/4, foldr/3, foldr/4) ?? mnesia:all keys/1
?? mnesia:index match object/4 (index match object/2) ?? mnesia:index read/3
?? mnesia:lock/2 (read lock table/1, write lock table/1) ?? mnesia:table_info/2
mnesia:write/3 (write/1, s write/1) mnesia:delete/3 (delete/1, s delete/1)
mnesia:delete object/3 (delete object/1, s delete object/1) mnesia:read/3 (read/1, wread/1) mnesia:match object/2 (match object/1) mnesia:select/3 (select/2)
mnesia:foldl/3 (foldl/4, foldr/3, foldr/4) mnesia:all keys/1
mnesia:index match object/4 (index match object/2) mnesia:index read/3
mnesia:lock/2 (read lock table/1, write lock table/1) mnesia:table_info/2
这些操作将在一个涉及到锁、日志、备份、checkpoint、subscription、提交协议等等的事务上下文里执行
但是,这些方法也可以在其他activity上下文里执行 Mnesia支持以下activity访问上下文:
Java代码
?? transaction ?? sync_transaciton ?? async_dirty ?? sync_dirty ?? ets
transaction sync_transaciton async_dirty sync_dirty ets
Fun作为参数传给mnesia:sync_transaction(Fun, [,Args])时会在同步事务上下文里执行 同步事务等待所有活动备份提交事务到硬盘才返回
多于在多个节点上执行并且希望确定远程节点更新已被执行的应用,以及联合事务写和dirty_read的应用,sync_transaction特别有用
sync_transaction对于需要频繁和大量可能对其他节点的Mnesia负载过重的更新的应用也有用
6,嵌套事务 事务可以任意嵌套
一个子事务必须运行在和父亲相同的进程里
当子事务终止时,子事务的调用者会得到返回值{aborted, Reason}并且子事务执行的任何任务都会擦除
如果子事务提交,则子事务写入的record会传播到父事务 当子事务终止时不会释放锁
一个嵌套事务序列创建的锁会一直保持直到最顶端的事务终止 而且,嵌套事务所做的更新只传播到父亲可见 不到最顶端事务结束,不会做最终的提交
这样,即使一个嵌套的事务返回{atomic, Val},如果外层的父事务失败,那么嵌套子事务也失败 具有嵌套事务与顶级事务相同语义的能力会让写操作Mnesia表的库函数更容易
Java代码
?? add_subscriber(S) ->
?? mnesia:transaction(fun() -> ?? case mneisa:read( ......
add_subscriber(S) ->
mnesia:transaction(fun() -> case mneisa:read( ......
该方法需要作为一个事务来调用
现在假设我们希望写一个方法,该方法调用add_subscriber/1方法,并且本身由一个事务上下文保护
通过在另一个事务里简单的调用add_subscriber/1,则创建了一个嵌套事务
7,模式匹配
当不能使用mnesia:read/3方法时,Mnesia提供了一些方法来对record进行模式匹配:
Java代码
?? mnesia:select(Tab, MatchSpecification, LockKind) -> ?? transaction abort | [ObjectList]
?? mnesia:select(Tab, MatchSpecification, NObjects, Lock) -> ?? transaction abort | {[Object], COntinuation} | '$end_of_table' ?? mnesia:select(cont) ->
?? transaction abort | {[Object], COntinuation} | '$end_of_table' ?? mnesia:match_object(Tab, Pattern, LockKind) -> ?? transaction abort | RecordList
mnesia:select(Tab, MatchSpecification, LockKind) ->
transaction abort | [ObjectList]
mnesia:select(Tab, MatchSpecification, NObjects, Lock) -> transaction abort | {[Object], COntinuation} | '$end_of_table' mnesia:select(cont) ->
transaction abort | {[Object], COntinuation} | '$end_of_table' mnesia:match_object(Tab, Pattern, LockKind) -> transaction abort | RecordList
这些方法对Tab表的所有记录匹配一个Pattern
没有必要对整张表执行昂贵的搜索,通过使用索引和pattern的key的绑定值,该方法所做真正的工作可能压缩为一些哈希查询
如果key部分绑定,则使用ordered_set表可能减少搜索空间
Java代码
?? Pat = #employee{sex = female, _ = '_'}, ?? F = fun() -> mnesia:match_object(Pat) end, ?? Females = mnesia:transaction(F).
Pat = #employee{sex = female, _ = '_'}, F = fun() -> mnesia:match_object(Pat) end, Females = mnesia:transaction(F).
8,迭代
Mnesia提供一些方法来迭代表里的所有记录:
Java代码
?? mnesia:foldl(Fun, Acc0, Tab) -> NewAcc | transaction abort ?? mnesia:foldr(Fun, Acc0, Tab) -> NewAcc | transaction abort
?? mnesia:foldl(Fun, Acc0, Tab, LockType) -> NewAcc | transaction abort ?? mneisa:foldr(Fun, Acc0, Tab, LockType) -> NewAcc | transaction abort
mnesia:foldl(Fun, Acc0, Tab) -> NewAcc | transaction abort mnesia:foldr(Fun, Acc0, Tab) -> NewAcc | transaction abort
mnesia:foldl(Fun, Acc0, Tab, LockType) -> NewAcc | transaction abort mneisa:foldr(Fun, Acc0, Tab, LockType) -> NewAcc | transaction abort