Erlang之Mnesia简单入门

2022-04-11 00:00:00 数据库 多个 事务 场景 节点

1.什么是Mnesia?
Mnesia在我理解里面就是一种数据库,是Erlang自带的,它支持事务,这是重要的事务就是要么做,要么全都不做,而且事务有几个重要的概念我们需要了解,因为只有我们知道事务有什么性质,才知道什么场景该用到事务,什么场景不需要。

2.事务几个重要概念
1.原子性(Atomicity)——每个事务都是一个不可分割的单元,要么整体成功,要么整体失败。执行过程一旦出现失败,事务便会整体回滚,不会对数据库造成任何影响。


2.一致性(Consistency)——执行多个事务时,即便实际执行时间有所交叠,终的效果应该像是各个事务按一定的顺序顺次执行一样,整个过程中数据库的状态始终保持完整和一致,这说明了事务可以用于并发的场景。


3.隔离性(Isolation)——每个事务都像是拥有一个自己的数据库副本一样,多个并发执行的事务不会相互干扰。在事务执行完毕之前任何人都观察不到事务的执行效果。


4.持久性(Durability)——事务执行成功后,它产生的变更便会生效。如果表保存在磁盘上,那么无论是重启还是崩溃都不会导致信息丢失。

3.基本操作
一个数据库无非是增删查改,本教程用于入门,所以有关并发编程,不会提及,场景是单点操作,还有安全权限等都没有,但以后会有相关更新,好了创建一个Mnesia基本可以分为以下几个步骤:

1.初始化Mnesia
1.启动节点:
erl -mnesia -dir '"路径"' -name/-sname nodename.
这一行代码,我们指定了mnesia创建的位置,和创建进程的名字。

2.建立数据库模式(schema);
所谓数据库模式 (schema)就是一些描述信息,其中记录着当前数据库中存有哪些表,表的详细情况又如何。一般来说不用关注它——它只是Mnesia用于跟踪自身数据的一种手段。当然,要想在多个节点上建立分布式数据库,就必须在所有节点上存放一份该模式的副本,以便让节点了解自己所存的数据的一般结构。为了防止Mnesia或整个Erlang节点关闭重启时丢失数据库信息,模式数据必须保存在磁盘上,存放路径由节点启动命令中的 -mnesia dir "..." 选项指定。(我们也可以让单个或多个节点,甚至所有节点仅在RAM中保存包括数据库模式在内的所有数据;但目前我们需要的是保存在磁盘上的持久化数据库。)这个例子比较简单,只需要在本地节点上建立数据库模式即可:



mnesia:create_schema(node[]).

3.启动Mnesia


mnesia:start().

2. 建立数据库表
好了做完了前面几步,部署并启动了mnesia,我们就要对数据库创建表,有以下几个步骤。

1.首先建立相应的record
record里面的成员对应我们创建出来的表的列名,当我们插入数据时就直接插入一个记录变量就行了。

2.利用mnesia:create_table(table_name, [Option])
创建表table_name就是表名,Option指明了这张表的性质,在Option所有选项之中,重要的一个就是 attributes ,几乎所有建表操作都会用上它。该选项用于指定表中所存记录的字段名。要是没它,Mnesia会假定记录中仅有两个字段,分别名为 key 和 val,我们还能指定表的类型,表一般有三种类型set,order_set,bag,若不知道这三种类型有什么不同,可以看我的上一篇ETS入门。代码举例:

mnesia:create_table(contributor,
[{type, bag}, {attributes, record_info(fields, contributor)}]).
我们创建了一个名为contributor的表,是以contributor记录为结构,类型是bag。


3. 对数据做一些基本查询
在我说CRUD之前,我要说明一下MNESIA在CRUD有分为2类,一种称为事务式的CRUD,一种称为脏操作,有什么不同呢,前者可以用于并发的场景,而且上下文必须是事务,不然很抛出exception exit: {aborted,no_transaction},拥有事务的全部特点,脏操作的速度更快,但是它不能用于并发的场景,什么时候应该用什么,要看你所需求的场景。

1.插入


mnesia:write(#user(id=Id,name=Name)).%事务式,要放在事务里面,不能单独
mnesia:dirty_write(#user(id=Id,name=Name)).%脏读


2.查找
查找有2种方式,一种是用qlc库,一种是mnesia自带的select,select在简单还好,但是在复杂查询的时候非常难搞,所以我推荐使用qlc,这里我就介绍qlc。

%qlc库
just_a_qlc() ->
mnesia:transaction(
fun() ->
Table = mnesia:table(user),%获取表
QH = qlc:q(([U#user.id || U<- Table])),%筛选
qlc:eval(QH)%获取相应列表
end
).



[{table_name,Key,Pid}] = mnesia:dirty_read(table_name,Key).%脏读,结果Pid就是结果
我们可以看出分为三个步骤,先获取表,然后第二步就是筛选和要什么要返回什么结果,第三步就能直接用eval()返回{ok,List}

3.删除
mnesia:dirty_delete_object(#user(id=Id,name=Name)).
mnesia:delete_boject(#user(id=Id,name=Name)).

相关文章