programming erlang ch17 - andstudy/forge GitHub Wiki
17์ฅ Erlang Database
ํ ์ดํฐ๋ฒ ์ด์ค ์ง์
- shop table
| ํญ๋ชฉ | ์๋ | ๊ฐ๊ฒฉ |
|---|---|---|
| apple | 20 | 2.3 |
| orange | 100 | 3.8 |
| pear | 200 | 3.6 |
| banana | 420 | 4.6 |
| potato | 2456 | 1.2 |
- cost table
| ์ด๋ฆ | ๊ฐ๊ฒฉ |
|---|---|
| apple | 1.5 |
| orange | 2.4 |
| pear | 2.2 |
| banana | 1.5 |
| potato | 0.6 |
ํ ์คํธ๋ฅผ ์ํ ์ค๋น๊ณผ์
1> c(test_mnesia).
{ok,test_mnesia}
2> test_mnesia:do_this_once().
stopped
=INFO REPORT==== 9-Aug-2008::07:42:46 ===
application: mnesia
exited: stopped
type: temporary
3> test_mnesia:start().
ok
4> test_mnesia:reset_tables().
{atomic,ok}
ํ ์ด๋ธ์์ ๋ชจ๋ ๋ฐ์ดํฐ ์ ํํ๊ธฐ
%% SQL equivalent
%% SELECT * FROM shop;
demo(select_shop) ->
do(qlc:q([X || X <- mnesia:table(shop)]));
ํ ์ด๋ธ์์ ๋ฐ์ดํฐ ์ถ์ถํ๊ธฐ
%% SQL equivalent
%% SELECT item, quantity FROM shop;
demo(select_some) ->
do(qlc:q([{X#shop.item, X#shop.quantity} || X <- mnesia:table(shop)]));
ํ ์ด๋ธ์์ ์กฐ๊ฑด์ ์ผ๋ก ๋ฐ์ดํฐ ์ ํํ๊ธฐ
%% SQL equivalent
%% SELECT shop.item FROM shop
%% WHERE shop.quantity < 250;
demo(reorder) ->
do(qlc:q([X#shop.item || X <- mnesia:table(shop),
X#shop.quantity < 250
]));
demo(reorder2) ->
do(qlc:q([{X#shop.item, X#shop.quantity} || X <- mnesia:table(shop),
X#shop.quantity < 250
]));
๋ ํ ์ด๋ธ๋ก๋ถํฐ ๋ฐ์ดํฐ ์กฐ์ธํ๊ธฐ
%% SQL equivalent
%% SELECT shop.item, shop.quantity, cost.name, cost.price
%% FROM shop, cost
%% WHERE shop.item = cost.name
%% AND cost.price < 2
%% AND shop.quantity < 250
demo(join2) ->
do(qlc:q([ {X#shop.item, Y#cost.price} || X <- mnesia:table(shop),
X#shop.quantity < 250,
Y <- mnesia:table(cost),
X#shop.item =:= Y#cost.name,
Y#cost.price < 2
]));
demo(join) ->
do(qlc:q([X#shop.item || X <- mnesia:table(shop),
X#shop.quantity < 250,
Y <- mnesia:table(cost),
X#shop.item =:= Y#cost.name,
Y#cost.price < 2
])).
๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์ดํฐ ์ถ๊ฐํ๊ณ ์ ๊ฑฐํ๊ธฐ
ํ(Row) ์ถ๊ฐํ๊ธฐ
add_shop_item(Name, Quantity, Cost) ->
Row = #shop{item=Name, quantity=Quantity, cost=Cost},
F = fun() ->
mnesia:write(Row)
end,
mnesia:transaction(F).
ํ(Row) ์ ๊ฑฐํ๊ธฐ
remove_shop_item(Item) ->
Oid = {shop, Item},
F = fun() ->
mnesia:delete(Oid)
end,
mnesia:transaction(F).
Mnesia ํธ๋์ญ์
- ๋น๊ด์ ์ ๊ธ ํ ์ด๋ธ์ ์ ๊ทผํ ๋ ๋ง๋ค, ๋ ์ฝ๋๋ ์ ์ฒด ํ ์ด๋ธ์ ๋ํด์ Lock DeadLock ์ด ์๊ธธ ๊บผ ๊ฐ๋ค๋ฉด, ํธ๋์ญ์ ์ค์ง
- ํธ๋์ญ์ ์ฝ๋๋ ์ฌ๋ฌ๋ฒ ์ํ๋ ์ ์๋ค.
-
ํธ๋์ญ์ ์คํจ์ ์ ์ ๋๊ธฐํ ๋ค์ ์๋
-
๋ถ์์ ํจ๊ณผ ๊ธ์ง - ์ด๋ฐ ์ฝ๋๋ ์๋์
F = fun() -> ... io:format("reading ..."), ...
ํธ๋์ญ์ ์ค๋จ์ํค๊ธฐ
farmer(Nwant) ->
%% Nwant = Number of oranges the farmer wants to buy
F = fun() ->
%% find the number of apples
[Apple] = mnesia:read({shop,apple}),
Napples = Apple#shop.quantity,
Apple1 = Apple#shop{quantity = Napples + 2*Nwant},
%% update the database
mnesia:write(Apple1),
%% find the number of oranges
[Orange] = mnesia:read({shop,orange}),
NOranges = Orange#shop.quantity,
if
NOranges >= Nwant ->
N1 = NOranges - Nwant,
Orange1 = Orange#shop{quantity=N1},
%% update the database
mnesia:write(Orange1);
true ->
%% Oops -- not enough oranges
mnesia:abort(oranges)
end
end,
mnesia:transaction(F).
์์ ์ฝ๋๋ฅผ ์ฐ์ ์คํ
test_mnesia:farmer(50).
ํธ๋์ญ์
: ์ฌ๊ณผ ๊ฐ์๋ฅผ N*2 ๋งํผ ์
๋ฐ์ดํธ
ํธ๋์ญ์
: ์ค๋ ์ง ๊ฐ์๋ฅผ N ๋งํผ ์ ๊ฑฐ
ํธ๋์ญ์
์ฑ๊ณต : ์ด์ ์ค๋ ์ง์ ๊ฐ์๋ 50
test_mnesia:farmer(100).
ํธ๋์ญ์
: ์ฌ๊ณผ ๊ฐ์๋ฅผ N*2 ๋งํผ ์
๋ฐ์ดํธ
ํธ๋์ญ์
: ์ค๋ ์ง ๊ฐ์๋ฅผ N ๋งํผ ์ ๊ฑฐ
ํธ๋์ญ์
์คํจ : 100๊ฐ๊ฐ ์๋จ์ ์๋ค.
ํธ๋์ญ์
์ทจ์
ํ ์ด๋ธ์ ๋ณต์กํ ๋ฐ์ดํฐ ์ ์ฅํ๊ธฐ
-
Mnesia ๋ ์ผ๋ญ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ์ ์ฅํ๋๋ก ์ค๊ณ : ๋ญ๋ ์ง ํ ์ด๋ธ์ ์ ์ฅ ๊ฐ๋ฅ
-
Mnesia ๋ fragmented tables ์ง์( ์๋ฒ๋ค์ด ํ ์ด๋ธ์ ๋ด์ฉ์ ๋๋ ๊ฐ์ง๊ณ ์๋๊ฑฐ)
add_plans() -> D1 = #design{id = {joe,1}, plan = {circle,10}}, D2 = #design{id = fred, plan = {rectangle,10,5}}, D3 = #design{id = {jane, {house,23}}, plan = {house, [{floor, 1, [{doors, 3}, {windows, 12}, {rooms, 5}]}, {floor, 2, [{doors, 2}, {rooms, 4}, {windows, 15}]}]}}, F = fun() -> mnesia:write(D1), mnesia:write(D2), mnesia:write(D3) end, mnesia:transaction(F). get_plan(PlanId) -> F = fun() -> mnesia:read({design, PlanId}) end, mnesia:transaction(F).
test_mnesia.erl
-module(test_mnesia).
-import(lists, [foreach/2]).
-compile(export_all).
%% IMPORTANT: The next line must be included
%% if we want to call qlc:q(...)
-include_lib("stdlib/include/qlc.hrl").
-record(shop, {item, quantity, cost}).
-record(cost, {name, price}).
-record(design, {id, plan}).
do_this_once() ->
mnesia:create_schema([node()]),
mnesia:start(),
mnesia:create_table(shop, [{disc_only_copies, [node()]}, {attributes, record_info(fields, shop)}]),
mnesia:create_table(cost, [{disc_only_copies, [node()]}, {attributes, record_info(fields, cost)}]),
mnesia:create_table(design, [{attributes, record_info(fields, design)}, {disc_only_copies, [node()]}]),
mnesia:stop().
start() ->
mnesia:start(),
mnesia:wait_for_tables([shop,cost,design], 20000).
%% SQL equivalent
%% SELECT * FROM shop;
demo(select_shop) ->
do(qlc:q([X || X <- mnesia:table(shop)]));
%% SQL equivalent
%% SELECT item, quantity FROM shop;
demo(select_some) ->
do(qlc:q([{X#shop.item, X#shop.quantity} || X <- mnesia:table(shop)]));
%% SQL equivalent
%% SELECT shop.item FROM shop
%% WHERE shop.quantity < 250;
demo(reorder) ->
do(qlc:q([X#shop.item || X <- mnesia:table(shop),
X#shop.quantity < 250
]));
demo(reorder2) ->
do(qlc:q([{X#shop.item, X#shop.quantity} || X <- mnesia:table(shop),
X#shop.quantity < 250
]));
%% SQL equivalent
%% SELECT shop.item, shop.quantity, cost.name, cost.price
%% FROM shop, cost
%% WHERE shop.item = cost.name
%% AND cost.price < 2
%% AND shop.quantity < 250
demo(join2) ->
do(qlc:q([ {X#shop.item, Y#cost.price} || X <- mnesia:table(shop),
X#shop.quantity < 250,
Y <- mnesia:table(cost),
X#shop.item =:= Y#cost.name,
Y#cost.price < 2
]));
demo(join) ->
do(qlc:q([X#shop.item || X <- mnesia:table(shop),
X#shop.quantity < 250,
Y <- mnesia:table(cost),
X#shop.item =:= Y#cost.name,
Y#cost.price < 2
])).
do(Q) ->
F = fun() ->
qlc:e(Q) end,
{atomic, Val} = mnesia:transaction(F),
Val.
example_tables() ->
[%% The shop table
{shop, apple, 20, 2.3},
{shop, orange, 100, 3.8},
{shop, pear, 200, 3.6},
{shop, banana, 420, 4.5},
{shop, potato, 2456, 1.2},
%% The cost table
{cost, apple, 1.5},
{cost, orange, 2.4},
{cost, pear, 2.2},
{cost, banana, 1.5},
{cost, potato, 0.6}
].
add_shop_item(Name, Quantity, Cost) ->
Row = #shop{item=Name, quantity=Quantity, cost=Cost},
F = fun() ->
mnesia:write(Row)
end,
mnesia:transaction(F).
remove_shop_item(Item) ->
Oid = {shop, Item},
F = fun() ->
mnesia:delete(Oid)
end,
mnesia:transaction(F).
farmer(Nwant) ->
%% Nwant = Number of oranges the farmer wants to buy
F = fun() ->
%% find the number of apples
[Apple] = mnesia:read({shop,apple}),
Napples = Apple#shop.quantity,
Apple1 = Apple#shop{quantity = Napples + 2*Nwant},
%% update the database
mnesia:write(Apple1),
%% find the number of oranges
[Orange] = mnesia:read({shop,orange}),
NOranges = Orange#shop.quantity,
if
NOranges >= Nwant ->
N1 = NOranges - Nwant,
Orange1 = Orange#shop{quantity=N1},
%% update the database
mnesia:write(Orange1);
true ->
%% Oops -- not enough oranges
mnesia:abort(oranges)
end
end,
mnesia:transaction(F).
reset_tables() ->
mnesia:clear_table(shop),
mnesia:clear_table(cost),
F = fun() ->
foreach(fun mnesia:write/1, example_tables())
end,
mnesia:transaction(F).
add_plans() ->
D1 = #design{id = {joe,1},
plan = {circle,10}},
D2 = #design{id = fred,
plan = {rectangle,10,5}},
D3 = #design{id = {jane, {house,23}},
plan = {house,
[{floor, 1,
[{doors, 3},
{windows, 12},
{rooms, 5}]},
{floor, 2,
[{doors, 2},
{rooms, 4},
{windows, 15}]}]}},
F = fun() ->
mnesia:write(D1),
mnesia:write(D2),
mnesia:write(D3)
end,
mnesia:transaction(F).
get_plan(PlanId) ->
F = fun() ->
mnesia:read({design, PlanId}) end,
mnesia:transaction(F).