Erlang中如何通过Mnesia实现按指定字段条件查询表记录
Mnesia实现按指定字段条件查询的方法
你要实现的按username字段匹配查询的逻辑,核心是编写正确的Mnesia匹配规范(Match Specification),直接用Mnesia原生接口即可实现对应SQL的查询效果。
实现代码
首先确保你的代码引入了tracked_connection记录的定义(即存放-record(...)语句的头文件),推荐用可读性更高的fun2ms方式生成匹配规则,避免硬编码字段位置出错:
% 引入记录定义的头文件,替换成你实际存放record定义的文件路径 -include("tracked_records.hrl"). %% @doc 按用户名查询匹配的连接记录,等价于Select * from tracked_connection where username = TargetUsername get_connections_by_username(TargetUsername) -> % 编译期将fun转换为Mnesia/ETS可识别的匹配规范 MatchSpec = ets:fun2ms( fun(#tracked_connection{username = U} = Conn) when U =:= TargetUsername -> Conn end ), % Mnesia操作默认包在事务中执行,保证数据一致性 case mnesia:transaction(fun() -> mnesia:select(tracked_connection, MatchSpec) end) of {atomic, Result} -> Result; % Result是符合条件的记录列表,无匹配则返回空列表 {aborted, Reason} -> erlang:error({query_failed, Reason}) end.
原生匹配规范写法(无record依赖/Shell调试用)
如果你不想依赖record头文件,或者要在Erlang Shell里直接调试,可以写原生的匹配元组,注意严格对应record的字段顺序:
你的tracked_connection记录本质是如下结构的标记元组:{tracked_connection, Id, Node, Vhost, Name, Pid, Protocol, Type, PeerHost, PeerPort, Username, ConnectedAt}
其中Username在元组的第11个位置,不需要匹配的字段用'_'占位,匹配规则写法和你之前写的全量查询格式一致:
% 替换'xxxxx'为你实际要匹配的username值,注意类型要和存储值完全一致(列表/二进制/原子不要混) MatchSpec = [ { {tracked_connection, '_', '_', '_', '_', '_', '_', '_', '_', '_', 'xxxxx', '_'}, [], ['$_'] } ], % 事务执行查询 {atomic, Result} = mnesia:transaction(fun() -> mnesia:select(tracked_connection, MatchSpec) end).
注意事项
- Mnesia默认要求所有读写操作在事务中执行,如果你追求极致性能且能接受短暂不一致的风险,可以用脏读接口
mnesia:dirty_select/2替换事务里的select调用,不推荐新手优先使用。 ets:fun2ms是编译期转换语法,不能直接在Erlang Shell中运行,Shell调试时先执行ms_transform:install().再写fun格式的匹配规则即可。- 匹配值的类型必须和Mnesia中存储的
username字段类型完全一致:如果存的是二进制串就写<<"xxxxx">>,存的是字符串列表就写"xxxxx",类型不匹配会查不到结果。 - 查询返回的结果是符合条件的
tracked_connection记录列表,和你写的SQL查询返回的结果集等价,无匹配数据时返回空列表。
内容的提问来源于stack exchange,提问作者Nuwan Sameera
相关产品推荐
相关产品推荐

