站内信DB设计实现
两年前,万仓一黍在博客园发了两篇关于站内信的设计实现博文,《群发“站内信”的实现》、《群发“站内信”的实现(续)》,其中阐述了他关于站内信群发的设计思想,很具有借鉴意义。他在设计时考虑到用户量和存储空间的占用等问题。当然,在他的两篇博文中强调了站内信的设计要考虑具体情况,没有理想的设计方案,他的设计只是对于群发(点到面)的解决方案。 在此简述一下他的设计方案,详细的可以移步万仓一黍的博客。
万仓一黍的设计方案:
站内信分为“点到点”和“点到面”,“点到点”属于私信,用户之间传递的信息,一对一传递。“点到面”,属于系统消息或者公共信息,属于一对多发送。
站内信的设计既要考虑到投递的准确性(也就是该收到的人能收到信息),也要考虑信息持久化存储空间占用问题,在他的第一篇博文中详细进行了介绍。
我们在此仅把第三种情况拿出来说明,也就是用户量为百万级,活跃用户只占其中的一部分。
数据库的设计:
表名:Message
ID:编号;SendID:发送者编号;RecID:接受者编号(如为0,则接受者为所有人);MessageID:站内信编号;Statue:站内信的查看状态;
表名:MessageText
ID:编号;Message:站内信的内容;PDate:站内信发送时间;
将一封Message分为两部分,一是存储内容,另一个是存储用户的查看状态。也就解决了关于群发信息的存储空间占用问题,不需要为每个用户插入相关数据。
另外考虑到百万级用户量,活跃用户只占其中的一部分,不可能在发送一封系统消息时,在Message表中为每一个用户插入一条状态(标记为未读),如果一百万用户,那么发送一条消息,就得往Message表中插入一百万条标记状态的数据,显然不具有可行性。所以万仓一黍提出换下思路:
在用户登录时检索Message和MessgaeText,将MessgaeText的ID 和Messgae 的MessageID 相匹配, 这样就有两种情况:
一、没有找到 RecID= 自己ID 并且MessageText中的消息ID不包含在Messgae的MessageID中
将此部分消息取出来,显示为该用户未读,在用户点击阅读的时候,将消息阅读状态写入Messgae表,Status=已读。
二、找到RecID=自己 并且 MessageText中的消息ID包含在Messgae的MessageID中,Status标记为已读
将此部分消息提前出来,显示为用户已读,如果想“删除”(当然是逻辑上的删除,并非物理数据库删除),设置该Status=删除。
对于上面的设计方案,设计系统消息群发全部用户,是很适合的。但是受众面越小(即“点到面”的面越小),就不太合适,所以我们需要在此设计方案上进行扩展。
只对上面提到的用户百万级且活跃用户只占一部分这种情况探讨。还是采用将消息内容和阅读状态分开设计。
我们将点到点和点到面综合到一起考虑,并且精细化这个“面”,不再是笼统的全部用户。“面”可以是具有某一角色的用户、某一用户组的用户甚至一些不具有任何公共特征的散列用户。
设计思路
概述如下:我们将消息分为私信(Private)、公共消息(Public)、系统消息(Global)(或者将公共消息和系统消息合并为公共消息也可以),视情况而定。
- 点到点:一对一发送,属于私信Private
- 点到个别:(接收面为百位用户)一对多(几百)发送,采用私信方式(Private)
- 点到局部:(接收面为具有某些公共特征如用户组、用户角色),属于公共消息(Public)
- 点到全部:一对全部发送,属于系统消息(Global)
数据库设计
表名:Message
ID:编号;RecID:接收者编号;MessageID:站内信编号;Statue:站内信的查看状态
表名:MessageText
ID:编号;SendID:发送者编号;Message:站内信的内容;Type:信息类型;Group:用户组ID; PostDate:站内信发送时间
其中Status状态有未读、已读、删除
Type类型有Private(私信)、Public(公共消息)、Global(系统消息)
第一种 点到点
点到点发送属于私信,比如A用户发送给B用户,首先在MessageText表中插入消息内容并且设置Type=Private,同时在Message表中插入一条记录设置RecID=B,Status=未读
用户B查找RecID=B,并且Staus为未读,Type=Private,显示为私信未读,点击阅读后改变Status=已读
用户B查找RecID=B,并且Staus为已读,Type=Private,显示为私信已读,删除设置Status=删除
第二种 点到个别
采用和私信相同的方式,在发送一条消息时在MessageText表中插入消息内容并且设置Type=Private,同时在Message表中插入多条记录设置RecID=各接收者ID,Status=未读
每个接收采用和私信一样的方式读取处理。
第三种 点到局部
点到局部是一对某角色或某用户组发送,例如管理员向普通用户组发送,在MessageText表插入消息内容,且设置Type=Public 和Group为用户组ID
用户登录后分两种情况:
1、未找到RecId=自己ID 且 MessageText中(Type=Public 和Group=自己所在组 ) 的消息ID不包含在Messgae的MessageID中
提取出来显示为用户公共消息未读,在用户点击阅读的时候,将消息阅读状态写入Messgae表,Status=已读。
2、找到RecId=自己ID 且 MessageText中(Type=Public 和Group=自己所在组 ) 的消息ID包含在Messgae的MessageID中
将此部分消息提取出来,显示为用户公共消息已读,如果想“删除”(当然是逻辑上的删除,并非物理数据库删除),设置该Status=删除。
注:此时可以不验证Group=自己所在组
第四种 点到全部
点到全部和点到局部采用类似的处理方式。例如管理员向普通用户组发送,在MessageText表插入消息内容,且设置Type=Global
用户登录后分两种情况:
1、未找到RecId=自己ID 且 MessageText中(Type=Global ) 的消息ID不包含在Messgae的MessageID中
提取出来显示为用户系统消息未读,在用户点击阅读的时候,将消息阅读状态写入Messgae表,Status=已读。
2、找到RecId=自己ID 且 MessageText中(Type=Global ) 的消息ID包含在Messgae的MessageID中
将此部分消息提取出来,显示为用户系统消息已读,如果想“删除”(逻辑上的删除,并非物理数据库删除),设置该Status=删除。
处理流程
我们再来看下整个处理流程,用户登录后系统是怎样提取和显示信息的。
用户登录后,采用Ajax异步加载、统计用户站内信
- Messgae表中RecId=自己ID 且Status=未读,显示为私信未读
- Messgae表中RecId=自己ID 且Status=已读 且 Type=Private,显示为私信已读
- Messgae表中未找到RecId=自己ID 且 MessageText中(Type=Public 和Group=自己所在组 ) 的消息ID不包含在Messgae的MessageID中,显示为公共消息未读
- Messgae表中找到RecId=自己ID 且 MessageText中(Type=Public ) 的消息ID包含在Messgae的MessageID中 ,显示为公共消息已读
- Messgae表中未找到RecId=自己ID 且 MessageText中(Type=Global ) 的消息ID不包含在Messgae的MessageID中 ,显示为系统消息未读
- Messgae表中找到RecId=自己ID 且 MessageText中(Type=Global ) 的消息ID包含在Messgae的MessageID中 ,显示为系统消息已读
原文地址:http://blog.csdn.net/yun_yg/article/details/19919421
站内信DB设计实现的更多相关文章
- ASP.NET 实现站内信功能(点对点发送,管理员群发)
正好这段时间在研究这个功能,还是得感谢这位大神,没有他的引路,我就不可能把站内信做出来. http://www.cnblogs.com/grenet/archive/2010/03/08/168065 ...
- 开源 免费 java CMS - FreeCMS2.1 会员站内信
项目地址:http://www.freeteam.cn/ 站内信 1.1.1 写信 从左側管理菜单点击写信进入. 输入收信人.标题.内容后点击发送button. 1.1.2 收件箱 从左側管理菜单点击 ...
- 2. SharePoint Online 开发,请联系qq512800530。加好备注。(不要发站内信。。。)
///(不要发站内信...) <meta name="keywords" content="SharePoint Online, SP Online, SPO, S ...
- 站内信,群发与全部发送。Gson解析result
/** * 发送站内信 */@Permission(Module.TZGL)@RequestMapping(value = "/sendznx", method = Request ...
- ThinkPHP---thinkphp完善站内信功能
[一]收件箱 分析 控制器:EmailController.class.php 方法:recBox(全称receive box收件箱) 模板文件:recBox.html 分步操作: 第一步:创建方法r ...
- c++小学期大作业攻略(四)任务系统+站内信
虽然比最早的预定晚了整整一个星期但这核心功能最后一篇终于还是来了. 如果你已经经历了用户系统的洗礼,相信代码实现应该已经没有太大的难度,所以我们重点关注一下设计好的流程. 一.任务系统 首先是新建任务 ...
- 站内信对话列表sql语句
- Lucene站内搜索的设计思路
正好近期部门有一个小需求需要做商品的搜索,虽然最终由于工作量等原因先做数据库搜索,我依然用刚接触的Lucene弄了一套自嗨. 首先看需求:搜索:根据商品标题和内容搜索 没错,就这么简单! 我想了想,数 ...
- SharePoint 2010 类似人人网站内信功能实施
简介:用SharePoint代码加实施的方式,完成类似人人网站内信功能,当然,实现的比较简单,样式也比较难看,只为给大家一个实施的简单思路,如有谬误,还请见谅.当然,还有就是截图比较长,当然为了让大家 ...
随机推荐
- 简单实现图片间的切换动画 主要用到ViewPager
简单实现图片间的切换动画 主要用到ViewPagerViewPager是android扩展包v4包中的类,这个类可以让用户左右切换当前的view.ViewPager类需要一个PagerAdapter适 ...
- python列表、字典与csv
在日常数据分析时最常打交道的是csv文件和list,dict类型.涉及到的主要需求有: 将一个二重列表[[],[]]写入到csv文件中 从文本文件中读取返回为列表 将一字典写入到csv文件中 从csv ...
- rhel-server-6.2-i386安装gcc、g++步骤
安装的版本:rhel-server-6.2-i386 RHEL 6.2默认是没有gcc和gcc-c++环境的,而且我也没有$购买正版服务.只能本地安装了,总结方法如下: 上传安装镜像rhel-serv ...
- 关于一个注册邮箱的demo
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...
- html5--canvas学习笔记
1. 添加<canvas>元素 right: <canvas id="myCanvas" width="300" height="3 ...
- extjs combobox 设置下拉时显示滚动条 设置显示条数
extjs在点击下拉时如果没有限制它的高度,那么它的默认最大高度是300,显示的时候就会显示300的高度,知道选项内容超过这个高度时才会自动显示滚动条,往往在有些时候我们希望让combobox显示一个 ...
- eclipse中如何导入jar包
如图,首先右键点击项目,选择最下面的properties, 然后进去之后点击java build path,右边会出来4个选项卡,选择libraries, 这时候最右边会有多个选项,第一个add ja ...
- MongoDB-固定集合 capped collection 操作 介绍
固定集合:capped collection 是性能出色的固定大小的集合,以LRU算法淘汰记录,自助维护集合中的对象的插入顺序,创建时预先制定大小,空间使用完,心对象取代旧的对象,保持最新的数据. 可 ...
- [Python笔记]第二篇:运算符、基本数据类型
本篇主要内容有:运算符 基本数据类型等 一.运算符 1.算术运算 2.比较运算 3.赋值运算 4.逻辑运算 5.成员运算 6.身份运算 7.位运算 8.运算符优先级 二.基本数据类型 1.整数:int ...
- Python学习笔记:05类
类 Python是面向对象的语言,面向对象最重要的三个优点有: 多态:多态使对象具备不同的行为方式.(可以认为声明了接口,但是实现方式可能多样) 封装:封装是对全局作用域中隐藏多余信息的原则(创建对象 ...