我正在实现一个带有聊天服务器和数据库逻辑的Erlang/OTP基本聊天应用程序(适用于Mnesia(。我想要一个数据库服务器作为中间人。这个聊天服务器和数据库都是分布式。因此,我可以用他们的节点名(通过使用聊天服务器(生成新的聊天用户。我可以为每个可用的用户节点初始化数据库,因此,数据库表将复制到每个节点我可以通过数据库逻辑代码访问数据。但不能用数据库服务器进行任何数据库操作。我启动了数据库服务器,输出:
(john@DESKTOP-RD414DV)7> database_server:start_link([node()|nodes()]).
{local,database_server} (<0.129.0>) starting...
这是数据库逻辑代码
-export([install/1, get_db/1, get_all_dbe/1, delete_db/1, store_db/4]).
-include_lib("stdlib/include/qlc.hrl").
-record(userDetails, {node,username, location, gender}).
%%initialize database
install(Nodes) ->
ok = mnesia:create_schema(Nodes),
rpc:multicall(Nodes, application, start, [mnesia]),
try
mnesia:table_info(type,userDetails)
catch
exit:_ ->
mnesia:create_table(userDetails, [{attributes, record_info(fields, userDetails)},
{type, bag},
{disc_copies, Nodes}])
end.
store_db(Node, Username, Location, Gender) ->
F = fun() ->
mnesia:write(#userDetails{node =Node, username = Username, location = Location, gender = Gender})
end,
mnesia:transaction(F).
get_db(Node) ->
F = fun() ->
Query = qlc:q([X || X <- mnesia:table(userDetails),
X#userDetails.node =:= Node]),
Results = qlc:e(Query),
lists:map(fun(Item) -> Item#userDetails.username end, Results)
end,
mnesia:transaction(F).
get_all_dbe(Node) ->
F = fun() ->
Query = qlc:q([X || X <- mnesia:table(userDetails),
X#userDetails.node =:= Node]),
Results = qlc:e(Query),
lists:map(fun(Item) -> {Item#userDetails.username, Item#userDetails.location, Item#userDetails.gender} end, Results)
end,
mnesia:transaction(F).
delete_db(Node) ->
F = fun() ->
Query = qlc:q([X || X <- mnesia:table(userDetails),
X#userDetails.node =:= Node]),
Results = qlc:e(Query),
FF = fun() ->
lists:foreach(fun(Result) -> mnesia:delete_object(Result) end, Results)
end,
mnesia:transaction(FF)
end,
mnesia:transaction(F).
这是数据库服务器代码:
-behaviour(gen_server).
-export([start_link/1, store/4, getalldb/1, delete/1]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
code_change/3]).
-define(SERVER, ?MODULE).
-record(database_server_state, {}).
%%%===================================================================
%%% Spawning and gen_server implementation
%%%===================================================================
start_link(Nodes) ->
gen_server:start_link({local, ?SERVER}, ?MODULE, Nodes, []).
init(Nodes) ->
process_flag(trap_exit, true),
io:format("~p (~p) starting...~n", [{local, ?MODULE}, self()]),
database_logic:install(Nodes),
{ok, #database_server_state{}}.
store(Node, Username, Location, Gender) ->
gen_server:call({local, ?MODULE}, {store_db, Node, Username, Location, Gender}).
%%getdb(Node) ->
%% gen_server:call({local, ?MODULE}, {get_db, Node}).
getalldb(Node) ->
gen_server:call({local, ?MODULE}, {get_all_db, Node}).
delete(Node) ->
gen_server:call({local, ?MODULE}, {delete, Node}).
handle_call({store_db, Node, Username, Location, Gender}, _From, State = #database_server_state{}) ->
database_logic:store_db(Node, Username, Location, Gender),
io:format("userdetails are saved!"),
{reply, ok, State};
%%handle_call({get_db, Node}, _From, State = #database_server_state{}) ->
%% X = database_logic:get_db(Node),
%% {_, [Name]} = X,
%% io:format("SENDER NAME: ~p~n", [Name]),
%% {reply, ok, State};
handle_call({get_all_db, Node}, _From, State = #database_server_state{}) ->
Y = database_logic:get_all_dbe(Node),
{_, [{Name, Location, Gender}]} = Y,
io:format("SENDER NAME: ~pt LOCATION: ~pt GENDER: ~p~n", [Name,Location,Gender]),
{reply, ok, State};
handle_call({delete, Node}, _From, State = #database_server_state{}) ->
database_logic:delete_db(Node),
io:format("~p node data deleted!", [Node]),
{reply, ok, State}.
handle_cast(_Request, State = #database_server_state{}) ->
{noreply, State}.
handle_info(_Info, State = #database_server_state{}) ->
{noreply, State}.
terminate(_Reason, _State = #database_server_state{}) ->
ok.
code_change(_OldVsn, State = #database_server_state{}, _Extra) ->
{ok, State}.
这个错误是在我执行存储、getdb等数据库操作时发现的。(它说NODEDOWN,但所有节点都在运行(
(john@DESKTOP-RD414DV)9> database_server: getalldb("mary@DESKTOP-RD414DV").
** exception exit: {{nodedown,database_server},
{gen_server,call,
[{local,database_server},
{get_all_db,"mary@DESKTOP-RD414DV"}]}}
in function gen_server:call/2 (gen_server.erl, line 367)
问题出现在gen_server:call
调用中:
gen_server:call({local, ?MODULE}, {get_all_db, Node}).
指定服务器进程名称的方式在start_link
和call
之间有所不同。在start_link
中,指定{local, myname}
是为了在本地节点上注册名称myname
,但在call
中,只指定myname
。
如果将一个包含两个元素的元组传递给gen_server:call
,它会将第一个元素视为进程名称,将第二个元素视为由节点名称。因此,在上面的代码中,它试图对节点database_server
上注册为local
的进程进行远程调用,但失败了,因为没有名为database_server
的节点(尤其是因为没有@
符号的节点名无效(。这就是为什么nodedown
是我们得到的错误。
因此,将gen_server:call
的行更改为类似的行
gen_server:call(?MODULE, {get_all_db, Node}).
您可以在gen_server
文档中看到这两种约定之间的差异。比较start_link
中使用的server_name()
类型规范和call
中使用的server_ref()
类型规范。