引言
在开发Web应用系统中,用户管理是一个核心的问题。管理用户,必不可少要管理用户的联系方式。一般情况下,人们会建立一个专门的联系方式表,包含电话、Email、QQ、MSN等联系方式。不难发现,即便我们考虑得再周全,也无法罗列全部的联系方式,如手机、座机、小灵通、大灵通、skype等。那么,如何才能使用户能够自由添加各种联系方式而不会影响系统本身呢?让我们来探讨这个问题的解决。
一、直接在用户表中增加联系方式字段
我们最先在管理用户的时候,会直接在用户表后面添加联系方式,如下表:
用户名
|
单位
|
phone
|
email
|
张三
|
A公司
|
01012345678
|
aa@163.com
|
(表1)
这在用户张三只有一个电话和一个Email地址的情况下,没有问题。但是,有一天,张三买了一个手机,并且把手机作为一种很重要的联系方式。开发人员很直观的想法就是在后面再加一个字段Mobile。
用户名
|
单位
|
phone
|
email
|
Mobile
|
张三
|
A公司
|
01012345678
|
aa@163.com
|
13912345678
|
(表2)
显而易见,这需要对用户表进行修改。这会为上层的程序带来麻烦。为了防止对用户表的修改,单独建立一个用户联系方式表是很自然的。
二、联系方式表与用户信息表分离
于是上面的用户表改变成下面两个表。
用户信息表
用户ID
|
用户名
|
单位
|
1
|
张三
|
A公司
|
2
|
李四
|
B公司
|
(表3)
联系方式表
ID
|
phone
|
Email
|
Mobile
|
用户ID
|
1
|
01012345678
|
aa@163.com
|
13912345678
|
1
|
2
|
02033333333
|
bb@gmail.com
|
13688888888
|
2
|
(表4)
这样一来,如果某一天又新增了一种联系方式,比如即时聊天工具QQ,MSN,我们无需改动用户信息表,只需要在联系方式表中增加相应字段就可以了。
是不是这样就已经令人满意了呢?
三、联系方式表扩展性问题
现在我们有一个新的用户名号王五,他既没有手机号,也没有Email,他只想留下QQ号作为联系方式。现在的表就变成这样:
用户信息表
用户ID
|
用户名
|
单位
|
1
|
张三
|
A公司
|
2
|
李四
|
B公司
|
3
|
王五
|
C公司
|
(表5)
联系方式表
ID
|
phone
|
Email
|
Mobile
|
QQ
|
用户ID
|
1
|
01012345678
|
aa@163.com
|
13912345678
|
|
1
|
2
|
02033333333
|
bb@gmail.com
|
13688888888
|
|
2
|
3
|
|
|
|
232678
|
3
|
(表6)
由于张三和李四输入信息时并没有QQ这一字段,所以张三、李四的联系方式记录的QQ字段的内容是空的。而王五的联系方式只有QQ这一字段有内容,其它几个字段都是空的。
现在,我们已经看出这种方式的问题了:
第一, 联系方式表中会一些字段的内容是空的,这会造成数据空间的浪费。
第二, 每增加一种联系方式,我们都需要在联系方式表中增加字段。这会使系统的维护变得非常复杂,还可能导致上层应用程序包括界面进行相应的修改。
于是我们便期望有一种更好的方法,能够解决联系方式扩充的问题,即:用户能够根据自己的需要添加联系方式,同时又不需要对数据库结构进行修改。
四、根据要素来构建联系方式表
好的,问题提出来了,我们就着手进行改进。先来进行一下理论的探讨:
联系方式是指联系一个人的手段或途径,联系方式最核心的要素是:方式+值 。即采用什么样的联系方式,这种联系方式的具体值是多少。如手机作为一种联系方式,值就是手机号码。QQ也可以作为一种联系方式,QQ号码就是联系方式的值。
从逻辑上讲,联系方式表的结构应该由其要素构成。即联系方式表的字段应该以方式和值作为最基本内容。
而我们上面建立的联系方式表,将phone、Email、Mobile、QQ等作为表的字段。而phone、Email等都是联系方式的内容,并不是联系方式表的要素本身。这是导致联系方式表不灵活的根本原因。
那么,现在我们就真正按照联系方式表的要素来搭建结构,而将Phone、Email等作为内容。
现在的联系方式表应该是这样:
ID
|
联系方式
|
值
|
1
|
Phone
|
13912345678
|
2
|
Email
|
aa@163.com
|
(表7)
这样我们就可以随意添加联系方式到表中了。当然,由于联系方式都是与用户对应的,所以联系方式表中还应该包含一个用户ID字段,即:
ID
|
联系方式
|
值
|
用户ID
|
1
|
Phone
|
13912345678
|
1 (张三的用户ID)
|
2
|
Email
|
aa@163.com
|
1
|
3
|
Phone
|
02033333333
|
2(李四的用户ID)
|
4
|
Email
|
bb@gmail.com
|
2
|
5
|
QQ
|
232678
|
3(王五的用户ID)
|
(表8)
这样,用户信息表与联系方式表就构成了一对多的关系。当然,这需要一种联系方式不是由两个人同时拥有,这也是与现实比较相符的。
五、让表结构更加优雅
前面的问题已经解决,我们是不是应该去喝庆功酒去了呢?
且慢,仔细看看最后的联系方式表(表8),有没有发现什么问题?在联系方式字段中,我们看到了两个Phone,两个Email。如果用户更多,看到的Phone和Email可能还会更多。
在录入数据的时候,会不会出现两个Phone不一致的情况,如一个首字母大写,一个首字母小写?当然,你会回答,可以在录入数据时一律进行大小写转换。
好吧,那个问题就此打住。我还有另一个问题:如果我想把Phone改成SitePhone,应该怎么办?做一次遍历,然后进行替换?
更好的方式:将联系方式这个字段单独取出来,建立另一个表,不但能解决刚才提出的这个问题,而且会收到更好的效果,请看:
ID
|
联系方式
|
1
|
Phone
|
2
|
Email
|
3
|
QQ
|
(表9)
ID
|
联系方式ID
|
值
|
用户ID
|
1
|
1
|
13912345678
|
1 (张三的用户ID)
|
2
|
2
|
aa@163.com
|
1
|
3
|
1
|
02033333333
|
2(李四的用户ID)
|
4
|
2
|
bb@gmail.com
|
2
|
5
|
3
|
232678
|
3(王五的用户ID)
|
(表10)
这样做有什么好处呢?第一,联系方式Phone、Email、QQ等在数据库中只出现了一次,便于对这些联系方式进行修改,也有利于保持数据的一致性。第二、可以对每种联系方式附加一些属性,如联系方式的用户数,这种统计数字可以用来分析用户群体使用联系方式的特征,从而改进商业策略。
好了,最后我们把建立的最终表呈现在下面吧:
1、用户信息表
用户ID
|
用户名
|
单位
|
1
|
张三
|
A公司
|
2
|
李四
|
B公司
|
3
|
王五
|
C公司
|
(表11)
2、联系方式表
ID
|
联系方式
|
数量
|
1
|
Phone
|
2
|
2
|
Email
|
2
|
3
|
QQ
|
1
|
(表12)
3、用户联系信息管理表
ID
|
联系方式ID
|
值
|
用户ID
|
1
|
1
|
13912345678
|
1
|
2
|
2
|
aa@163.com
|
1
|
3
|
1
|
02033333333
|
2
|
4
|
2
|
bb@gmail.com
|
2
|
5
|
3
|
232678
|
3
|
(表13)
六、题外话
就设计用户联系方式表这一简单的话题,我们一路走来。笔者认为,由表及里地思考对于我们设计可扩展的、易于维护的数据库系统非常有好处,可以为后续的管理、维护以及升级带来不少便利,省下不少精力和时间。我们的这种思考可以举一反三应用到选课数据库设计、用户权限管理数据库设计等方面。
当然,我们可以再上升到理论的层次:前面所做的工作事实上是对数据库设计的正规化形式的体现。如果对数据库进行正规化设计,请参阅我的另一篇笔记:http://blog.csdn.net/z365days/archive/2007/10/25/1842608.aspx
posted on 2007-10-30 10:26
CPP&&设计模式小屋 阅读(793)
评论(2) 编辑 收藏 引用 所属分类:
数据库