Database 用记忆保持关系完整性

Database 用记忆保持关系完整性,database,erlang,mnesia,Database,Erlang,Mnesia,我最近一直在潜心研究Erlang,我决定使用Mnesia来做我的数据库工作,因为它可以毫无问题地存储任何类型的Erlang数据结构,可以轻松扩展,可以与列表理解一起使用,等等 来自标准SQL数据库的大多数行可以而且应该由主键标识,主键通常是一个自动递增的整数。默认情况下,Mnesia将行的第一个字段视为其键。据我所知,它也没有办法拥有一个自动递增的整数键 假设我有这些虚构的记录代表我的表: -record(user, {name, salt, pass_hash, email}). -recor

我最近一直在潜心研究Erlang,我决定使用Mnesia来做我的数据库工作,因为它可以毫无问题地存储任何类型的Erlang数据结构,可以轻松扩展,可以与列表理解一起使用,等等

来自标准SQL数据库的大多数行可以而且应该由主键标识,主键通常是一个自动递增的整数。默认情况下,Mnesia将行的第一个字段视为其键。据我所知,它也没有办法拥有一个自动递增的整数键

假设我有这些虚构的记录代表我的表:

-record(user, {name, salt, pass_hash, email}).
-record(entry, {title, body, slug}).
-record(user_entry, {user_name, entry_title}).
我认为在某些情况下,使用用户名可能已经足够好了,比如条目标题,以便识别资源,但是如何保持完整性呢

假设用户更改了名称,或者条目的标题在编辑后更改。如何确保我的数据仍然正确相关?无论如何放置,在每个表发生更改时使用用户名更新它听起来都是一个糟糕的主意

在Mnesia中实现某种主键系统的最佳方式是什么


另外,如果第一个字段通常是键,那么像“user_entry”这样的中间表将如何处理?否则,在Mnesia中表示多对多关系的更好方法是什么?

我更喜欢使用guid而不是自动递增int作为人工外键。有一个在 GitHub,或者您可以使用
{now(),node()}
,因为
now/0
doc说:“还可以保证对这个BIF的后续调用会返回不断增加的值。”

在我看来,独立于数据库系统,使用可以更改的内容作为主键是一个坏主意

不要忘记,你不需要将记忆中的数据标准化,即使是第一个标准形式;在您的示例中,我将考虑以下结构:

-record(user, {id, name, salt, pass_hash, email, entries}).
-record(entry, {id, title, body, slug, users}).
其中
条目
用户
是ID列表。当然,这取决于您想要的查询


编辑:固定为多对多而不是多对一。

Mnesia支持序列(自动递增整数),形式为
Mnesia:dirty\u update\u计数器(表、键、增量)
。要使用它,您需要一个具有两个属性Key和Count的表。尽管名称不同,dirty_update_计数器是原子计数器,即使它不在事务内部运行

Ulf Wiger做了一些工作,在他的工作中在mnesia之上提供了典型的RDBMS特性。他的代码提供外键约束、参数化索引、字段值约束等。不幸的是,这段代码已经两年没有更新了,如果没有相当多的Erlang经验,可能很难运行

在设计和使用mnesia时,您应该记住,mnesia不是关系数据库。它是一个事务性的键/值存储,在不进行正常化时更易于使用

如果用户名是唯一的,则可以使用模式:

-record(user, {name, salt, pass_hash, email}).
-record(entry, {posted, title, body, slug, user_name}).
其中
post
是文章上载时的erlang:now()时间<如果您经常需要为用户检索所有文章的列表,则code>user\u name可能需要二级索引。由于此数据被拆分为两个表,因此必须在应用程序代码中强制执行任何完整性约束(例如,不接受没有有效用户名的条目)

mnesia中的每个字段值都可以是任何erlang术语,因此,如果您在任何特定字段上都找不到唯一的键,您通常可以组合一些字段以获得一个始终唯一的值—可能是{Username,DatePosted,TimePosted}。Mnesia允许您通过
Mnesia:select(表,MatchSpec)
搜索部分键。matchspec很难手工编写,因此请记住,
ets:fun2ms/1
可以为您将psuedo-erlang函数转换为matchspec

在本例中,fun2ms为我们生成一个matchspec,用于搜索博客条目表
-记录(条目,{key,title,slug,body})。
其中key是
{Username,{Year,Month,Day},{Hour,Minute,Second}
-作者的用户名以及文章发布的日期和时间。下面的示例通过
TargetUsername
检索2008年12月期间所有博客文章的标题

ets:fun2ms(fun (#entry{key={U, {Y,M,_D}, _Time}, title=T})
             when U=:=TargetUsername, Y=:=2008, M=:=12 ->
               T
           end).

这真的是好办法吗?似乎make_ref/0会在重新启动shell后重置其计数,并且会有多个类似的值。这难道不意味着在服务器重新启动后,您可能会得到坏密钥吗?将它与now/0结合可能会有所帮助。实际上,将now/0与node/0结合可能更好。或者,您可以使用uuid模块:我认为“where”应该改为“when”。谢谢您的精彩解释。