2017-02-12 26 views
0

我为自己创建了一个数据库,并且我有一个注册表单,要求他们输入姓名,密码,电子邮件,移动设备,年龄和位置。它有希望成为一个约会网站。MySQL中国家的数据类型

到目前为止,我有(我的数据库)

create table members(
    user VARCHAR(16), 
    password VARCHAR(16), 
    email VARCHAR(320), 
    mobile VARCHAR(15), 
    age INT(3) 
    #location ??? 
    INDEX(user(6)); 
) 

编辑忘了问问题

应该使用什么样的数据类型为location和数据库是否看起来足够安全?

该位置是按国家和由下拉菜单选择。

+0

您错过了提问:-) –

+0

@PaulSpiegel谢谢!完全忘记:) – smithster

+0

“位置”只是国家,还是更详细的位置? –

回答

3

该数据库是否将眼光够安全吗?

不,这需要一点时间来解释。

让我们从所有这些限制开始。过度热心地使用色谱柱限制是一个非常普遍的问题。

这些限制的工作方式常常被误解,例如您询问安全问题,或者您可能认为您节省了空间。真正的问题是它难以编码对软件的其余部分如何进入数据库的不必要限制,并且您的限制非常吝啬。

您问这是否使表更安全。列限制并不是关于安全性的,尽管我猜他们理论上不让某人填满磁盘,但这并不是你拥有的限制。

例如,您的密码限制为16个字符。这不是数据库应该做的决定,而是安全考虑。当您稍后查看密码安全性时,您会发现16个字符的密码几乎不够用。你想要更像64或128的东西,这将需要昂贵的alter table

更重要的是,您将存储密码清晰。这是一个很大的安全问题。

那么你有电子邮件(大概电子邮件地址)设置为320个字符?!这是一个电子邮件地址!但用户只能得到16个名字?

一个常见的误解是,这些限制减少了磁盘使用量。他们不。 varchar将只存储该行所需的数量。 age INT(3)不使用比age INT更少的空间,它是固定大小。 好的,它可以确保你的约会网站上没有任何12938岁的人 甚至没有这样做。这只是多少字段得到显示,这是肯定不是应该在您的架构中的东西。 MySQL做了一些奇怪的事情。

你可以使用一个unsigned tinyint存储从0到255的1个字节......但一旦你担心个别字节它会变得愚蠢。这一切都没有实际意义,根本不存储他们的年龄。储存他们的生日。因为人们变老了。


关于使用限制的错误方法,有什么正确的方法?

限制是为了执行数据完整性(和技术限制,请参阅评论)。就是这样。您希望创建一个足够灵活的模式来支持您的应用程序希望成为的任何应用程序,同时还可以确保数据是它所说的数据,而无需不断地再次猜测它。

一个更好的模式可能是这样的:

create table members(
    id primary key auto_increment, 

    username varchar(64) unique, 
    password_hash varchar(128), 
    email varchar(64) unique, 
    mobile varchar(32), 
    birthday datetime, 

    location integer references(locations), 

    index(birthday) 
) 

你的表是缺少一个主键,这是一个很大的问题。用户名可以改变,并且你不希望引用该用户的所有内容都会中断。相反,使用一个简单的自动递增整数。 “但我不会让用户改变他们的名字!”是的,请记住我刚才提到的关于软件硬编码限制的数据模型?多年来,您如何构建您的架构具有影响力。

本来我把所有的限制从领域中删除,并将它们切换到无限制text。他们都没有一个令人信服的限制理由。除非你有很好的理由,否则只需使用textvarchar。限制在数据模型中处理,可由程序员和设计人员更改。 A textvarchar字段只会使用尽可能多的空间。

......但是@PaulSpiegel在评论中指出MySQL's has limitations on how big a field it will index。我习惯于没有这种限制的Postgres。所以我将它们转换为varchar,并挑选了大量限制。技术限制可能是使用限制的理由。

username(不user因为这可以参考整个用户,而不仅仅是他们的名字)和email已标记unique。这是关于数据完整性的,你不希望两个人使用相同的用户名,并且你想要确保每个帐户都有一个单一的联系点(你可能会说这是把行为放在数据库中,你可能是对的,但删除唯一索引比添加索引更容易)。

然后我们来看到明显的安全问题。 从不存储密码!永远。永远永远。相反,存储密码的散列。如果您不知道我在说什么,请立即停止并阅读Salted Password Hashing - Doing it Right

代替存储age,我们将它们的birthday作为datetime存储。存储用户的年龄并不是展望未来,明年会发生什么?随着他们的生日,你可以计算他们的年龄,甚至给他们生日礼物!通过将其存储为datetime,您可以使用MySQL's confusing date and time functions对其进行各种日期计算。

你问及如何处理位置。位置可能意味着很多事情,并且可能会变得非常复杂。这不是您现在需要做出的决定,因此最好做到这一点,以便稍后可以对其进行扩展和更改。把它放在自己的表中,并用外键引用它。我们稍后再回来,这是整个观点。

最后,索引。您的磁盘空间不需要太过简单,只需要存储用户名的前6个字符!通过用户名查看用户将非常非常常见,并给它一个完整的索引。但我们不需要一个,声明一个列unique给它一个索引。

索引可以提高查询性能,但它们也可以占用磁盘空间并降低插入速度。而不是事先对索引疯狂,等到你看到你将要做什么查询以及表现如何。我输入的唯一明确索引是birthday,因为我非常确定约会网站正在按年龄进行限制。


这里缺少的是您的数据模型。这是数据之上的代码,例如Member类。它将处理成员可以执行的所有事情,包括访问数据库以及限制应该是什么。模型是触及数据库的唯一东西,其余的代码调用模型上的方法。这可以让数据库更改而不用担心影响整个项目。

这就是所谓的模型 - 视图 - 控制器或MVC,这是数据驱动应用程序编码的基本方式。 Ruby On Rails就是一个很好的例子。看看MVC。


好的,位置。我们已经制作了location自己的表格。这使得它成为一个抽象的概念,而不是members表中的某些硬编码字段。

位置会变得非常复杂。所以我们会保持简单。从其他用户希望知道的一些基本信息开始:​​谁在附近。最低限度是邮政编码和国家,你可以从中找出很多。你可能也想保持城市和州,因为这是人们想要找到人的另一种方式。

create table locations (
    id integer primary key, 

    city text, 
    province text, 
    country text, 
    postal_code text 
); 

制作位置模型来封装和管理位置数据。

现在,您可以随心所欲地管理位置数据,而不会搞乱成员表。你可以做什么@PaulSpiegel建议,并建立一个所有国家及其名称的表格,以便在其他代码中引用并确保它们使用的是真实的国家(数据完整性)。您可以使用他们的邮政编码来获取他们的城市和省份。您可以存储GPS数据,如果他们会给你的。


所以,唔......如果你刚开始这可能会似乎势不可挡。数据建模很复杂。这不一定很难,只需要考虑很多移动部件和事物,以便您的应用程序不受您的架构限制。您可能必须使用过于简单的模式来制作一些真正理解的应用程序。

让我们看看我能不能熬下来。

  • 有一个简单的主键。
  • 避免列限制。
  • 永远不要将密码存储在明文中。
  • 将复杂性推送到自己的表中。
  • 存储您可以从(生日,邮政编码)中派生更多的东西。
+1

感谢您的详细信息!非常满意:) – smithster

+0

两点:1)“它确保你没有任何12938” - 它不。 INT(3)'在技术上与'INT(10)'相同。 '3'只是显示长度(例如用于ZEROFILL)。但是你可以使用'TINYINT'。 2)AFAIK你不能在没有lentgh的情况下在'TEXT'列上定义唯一的索引。因此'email'的长度应该是有限的。但总的来说 - 伟大的文章:-) –

+0

@PaulSpiegel我不使用MySQL,我使用Postgres,所以关于MySQL的细节表示赞赏,并继续编辑任何技术失误。如果'text'不能是唯一的,那么使用'varchar'就没有限制。 – Schwern

1

创建一个countries表,该表将存储您想要支持的所有国家/地区。

code CHAR(2) PRIMARY KEY, 
name VARCHAR(50) NOT NULL UNIQUE 

code | name 
=====|===== 
    FR | France 
    GB | United Kingdom 
    US | United States of America 
    .. | ... 

你可以找到ISO 3166-1代码在这里:https://en.wikipedia.org/wiki/ISO_3166-1

使用此表来创建下拉菜单。

在你的成员表中定义的列

country_code CHAR(2) NOT NULL 

这应该是一个外键引用countries

CONSTRAINT FOREIGN KEY fk_members_countries (country_code) REFERENCES countries(code) 
+0

所以,我应该'位置'替换为'国家'? – smithster

+0

@smithster为什么叫它的位置,如果它是一个国家?如果它实际上是一个国家代码,为什么称它为国家?以最佳方式为每一列提供描述存储值的名称。 –

+0

那么把'location'改成'country_code'? – smithster