mnesia は、MySQL や他の RDBMS のように自動インクリメント機能をサポートしていないことに気付きました。mnesia のドキュメントで説明されているカウンターは、あまりよく説明されていません。たとえば、ドキュメント全体でカウンターを操作する関数が1つ見つかりました
mnesia:dirty_update_counter({Tab::atom(),Key::any()}, Val::positive_integer())
したがって、これはしばらくの間、タイプのレコードで機能するため、私を悩ませていました
{タブ名、キー、整数}これも不明確であり、おそらく Erlang の本や mnesia のドキュメントで説明する例が提供されていないためです.これにより、私は独自のカウンター操作 API を実装する必要がありました.私のレコードに「カウンター」と呼ばれるフィールドを含めてから、カウンターを持つことを目的としたテーブルにレコードを追加する時点で、私は次のようにします:
#recordname{field1 = Val1,...,counter = auto_increment(?THIS_TABLE)}
カウンタ フィールドの位置は重要ではありません。API は次のように実装されます。
%% @doc この関数は、テーブル
%% に新しいレコードを書き込んでいるときに、その結果をレコードのカウンタ フィールドに与えることによって呼び出されます。
%% @end
%%
%% @spec auto_increment(TableName::atom()) -> 整数() | 退出(理由)
auto_increment(テーブル名)-> ケースリスト:member(counter,table_info(TableName,attributes)) of false -> erlang:exit({counter,field,not_found,in_table,TableName}); true -> table_info(テーブル名,サイズ) + 1 終わり。
table_info(タブ,項目)-> F = fun({X,Y}) -> mnesia:table_info(X,Y) end, mnesia:activity(transaction,F,[{Tab,Item}],mnesia_frag).
これを説明するために、カウンターフィールドがテーブルの属性でない場合、このコードを実行しようとしているプロセスを強制的に終了させます。 catch ...) of body 、彼らは何が悪いのか簡単にわかります。または、このコード フラグメントがトランザクション内で実行されているかどうかを確認することもできます。mnesia:is_transaction()
これが true を返す場合は を呼び出しmnesia:abort/1
、false の場合は理由を付けて終了できます。また、mnesia アクティビティ関数で mnesia_frag を使用します。テーブルの断片化プロパティに関係なく動作します。 を使用するmnesia:transaction(Fun)
と、この呼び出しは最初のフラグメント (ベース テーブル) にのみアクセスするため、断片化されたテーブルの一貫性が失われます。
ここで、カウンターを含むテーブルからレコードが削除されると、テーブル内の順序を再配置する必要があります。この操作は、テーブル全体での反復が必要なため、コストがかかります。カウンター = 5 のレコードを削除すると、カウンター = 6 のレコードをカウンター = 5 にする必要があるため、パターンに従います。カウンターが削除されたものより大きかったすべてのレコードは、デクリメントする必要があります。したがって、削除されたカウンター値と TableName を渡すことで、mnesia:foldl/3 or mnesia:foldr/3 , the difference between these two comes in only with ordered table types
これを処理する関数を使用してテーブルを反復処理できます。
auto_decrement(Counter_deleted,TableName)-> Attrs = table_info(TableName,attributes), ケースリスト:メンバー(カウンター、属性) false -> erlang:exit({counter,field,not_found,in_table,TableName}); 真 -> Counter_position = 位置 (カウンター、属性) + 1、 反復子 = fun(Rec,_) when element(Counter_position,Rec) > Counter_deleted -> カウント = 要素(Counter_position,Rec), New_rec = erlang:setelement(Counter_position,Rec,Count - 1), mnesia:write(TableName,New_rec,read), []; (_,_) -> [] 終わり、 Find = fun({Fun,Table}) -> mnesia:foldl(Fun, [],Table) end, mnesia:activity(transaction,Find,[{Iterator,TableName}],mnesia_frag) 終わり。
レコードからカウンター フィールドの位置を動的に見つけるのに役立つコードがあることに気付きました。これを行うのに役立つコードを以下に示します。
位置(_,[]) -> -1; 位置(値,リスト)-> 検索 (リスト: メンバー (値、リスト)、値、リスト、1)。 検索 (false,_,_,_) -> -1; find(true,V,[V|_],N)-> N; find(真,V,[_|X],N)-> (V、X、N + 1) を検索します。 find(V,[V|_],N)-> N; find(V,[_|X],N) -> find(V,X,N + 1).
これは、このモジュールがプログラマーのカウンターを支援するために、プログラマーのレコードを認識してはならないためですelement(N::integer(),Tuple::tuple())
。レコードの表現を動的に。
これらの 2 つの関数は私のために働いており、auto_increment が mnesia
に実装されるまでまだ機能しています。
たとえば、qlc (クエリ リスト内包表記) を使用して、動的な制約を持つテーブルをクエリする場合、次のコードを検討してください。
select(Q)-> F = fun(QH) -> qlc:e(QH) 終わり、 mnesia:activity(transaction,F,[Q],mnesia_frag). read_by_custom_validation(Validation_fun,From_table)-> select(qlc:q([X || X <- mnesia:table(From_table),Validation_fun(X) == true])))。 %% 2 つの関数を適用しています.... find_records_with_counter(From_this,To_that) when
is_integer(From_this),is_integer(To_that),To_that > From_this -> F = fun(#recordName{counter = N}) when N >= From_this,N =< To_That -> true; (_) -> 偽 終わり、 read_by_custom_validation(F,TableName)。
在庫管理システムでは、これは機能しています...
(stock_project@127.0.0.1)6> ストック:get_items_in_range(1,4)。 [#item{item_id = "D694",name = "セメント", time_stamp = {"2010 年 12 月 30 日","午前 11:29:10"}, min_stock = 500,units = "bags",unit_cost = 20000, 状態 = 利用可能、last_modified = 未定義、 カテゴリ = "建材",カウンター = 1}, #item{item_id = "131B",name = "ネイル", time_stamp = {"2010 年 12 月 30 日","午前 11:29:10"}, min_stock = 20000、units = "kg"、unit_cost = 1000、 状態 = 利用可能、last_modified = 未定義、 カテゴリ = "建材",カウンター = 2}, #item{item_id = "FDD9",name = "鉄板", time_stamp = {"2010 年 12 月 30 日","午前 11:29:10"}, min_stock = 20,units = "バー",unit_cost = 50000, 状態 = 利用可能、last_modified = 未定義、 カテゴリ = "建材",カウンター = 3}, #item{item_id = "09D4",name = "ペイント", time_stamp = {"2010 年 12 月 30 日","午前 11:29:10"}, min_stock = 30000,units = "tins",unit_cost = 5000, 状態 = 利用可能、last_modified = 未定義、 カテゴリ = "建材",カウンター = 4}] (stock_project@127.0.0.1)7>
これは私のために働いています。他にどのようにカウンターを処理すればよいか教えてください。または、その側でそれらをどのように処理するか教えてください.