类似邮件收发功能的相关数据库设计或逻辑处理记录
文章目录
一、梳理需求逻辑或需要思考的问题说明
- 邮件系统对于每个用户来说,都有各自的收件箱和发件箱,即发送和接收邮件是毎个用户都有的功能;
- 在发件箱中,邮件和用户是一对一的关系。用户编辑好要发送的邮件后可以选择发送,也可以选择保存草稿。所以发件箱的逻辑比较简单;
- 在收件箱中,邮件和用户是一对多的关系。用户可对收件箱的每个邮件进行处理,如回复、转发、删除、回执等操作,注意,这些操作每个用户之间是独立的。举个例子,用扁1001给1002和1003同时发了条邮件 a,那么 对于这条邮件 a ,1002和1003都在自己的收件箱可以査看并且可以进行相关操作,我们要需要思考的是,如果1002删除了邮件 a ,1002在自己的收件箱看不到邮件 a 了,但不能影响1003能正常查看和操作邮件 a ,这里是我们要思考如何设计的一个点;
- 另外,需要审批功能,逻辑是,邮件发送后,需要通过审批流程处理后,收件方才能收到并对该邮件进行相关操作,因此这里也需要思考的逻辑是,邮件发送后,需要发起审批流程,审批人可以査着到待审批的邮件数据,并进行处理(通过/拒绝),如果审批通过,收件方才能收到该邮件并进行相应的操作;
- 收件方收到邮件后,可对该邮件进行的操作主要包括:回复、转发、回执、删除。其中,回执即代表了对该邮件是否已处理,处理的结果是接受或拒绝。我们通过是否回执来区分该邮件是否已处理。
读到这里前,可以先思考一下以上5点应该怎么设计,尤其是第3点,设计中出现的问題是什么?我在设计并处理逻辑的时候,遇到的问题主要是,收件方在处理邮件状态时会乱套,一开始,我是这么想的,如1001给1002和1003分别发送邮件 a ,这时我会分别存储一条邮件信息和存储一条邮件状态信息(发送成功)在相应表中,然后我通过这两张表查询邮件数据,1002和1003就可以分别在自己的收件箱可以查看邮件 a ,这时,当1002对邮件 a 进行操作时,如1002想要删除邮件 a ,我最直接想到的是,那就删除刚才存储的状态信息(这样的好处是我只是删除了个状态信息,邮件的信息还会存在库中);但是会发现1003也查看不到这条邮件 a,其他的操作也是类似的问题,显然是不合理的。
二、方案一(不推荐,一开始不成熟的想法)
(如果觉得篇幅太长累了,可以跳过这节,直接阅读第三章节的方案二)
基于第一章节的5点,以及我遇到的主要问题,我开始考虑的一个不太成熟的设计方案如下:
-
我一开始想的是给记录邮件状态的表里加字段表示不同的状态,如添加字段:发送状态、删除状态、回执状态等,比如1002删除了邮件 a 那么在邮件状态表中删除状态这个字段添加1002,其他操作同理在对应的状态字段中记录用户编号,这样我只需要在获取数据的时候根据这些状态字段过滤一下就可以,比如1002用户,我们获取1002收到的邮件数据时,在邮件状态表里诵过邮件 ID 查询邮件状态,如邮件 a 在邮件状态表中的记果中删除状态字段有1002,那就说明1002删除了该邮件,则不展示邮件a, 其他操作同理;
-
这样设计的好处是:邮件状态表和邮件表是一对应的,即一个邮件 D 在邮件表和由邮件状态表中只有一条数据;但这样设计有以下三个缺点:
- 每次操作需要去修改邮件状态表,给相应的字段中添加数据这样其实是很麻烦或者容易出错的
- 并且在查询邮件数据时,也是有点麻烦的;
- 给表中添加过多的状态字段也有点笕余不好扩展,如果有更多的邮件状态,还需要修改数据库表。
期间也想了好几种设计思路,这里就不展开讲了下面开始讲下目前使用的比校合理和优化的设计思路和处理逻辑。(其实现在看来,这个设计逻辑挺简单的可是开始我就没有想到。)
三、方案二:比较合理和优化的方案(推荐)
以下针对第一章节的5点和我遇到的主要问题来说明:
-
基于第一章节的5点,比较清晰地是我们至少需要两张表,存储邮件信息的表(MAIL)、存储邮邮件状态信息的表(MAlL _ STATUS)。其中, MAIL 表中主要包括的字段用户信息(发件人信息、收件人信息)、邮件 ID 、邮件内容等; MAIL_STATUS 表中主要包括的字段用户信息,邮件 ID 邮件状态,邮箱类型(0收件箱/1发件箱)
-
针对第一章节的第2点,很明显,我们需要两种状态:发送成功状态、保存草稿成功状态
-
针对第一章节的第3点,也是最主要要说明的一点。因为对于收件箱功能,邮件和用户是一对多的关系,并且用户可能会对用一个邮件信息进行处理是独立的互不影响的。针对这个问题,以及方案一的缺点,以下介绍目前使用的比较合理的方案:
-
MAIL_STATUS 表包含字段:用户信息,邮件 ID ,邮件状态,邮箱类型(0收件箱/1发件箱)等。当发件人1001发送一份邮件 a 给指定的收件人1002、1003时,我会在 MAIL 表中存储邮件 a 的信息,如(‘1001’,‘1002,1003’,mailiDxxx’,‘mailContent’,…);同时,在 MAIL_STATUS 中插入3条记录状态**(注意这里),其中一条状态信息是针对发件人1001,对于1001来说这条邮件 a 应该出现在他的发件箱中,因此我们存储一条状态信息(‘1001’,'mailDxxx ',1,1)在 MAIL_STATUS中;另外两条状态信息是针对收件人的,即对于1002和1003来说邮件 a 应该出现在其收件箱中,因此我们分别存储两条状态信息在 MAIL _ STATUS 中,如(‘1002’,‘mailiDxxx’,4,0)和(‘1003’, 'mailDxxx '4,0 )**;
-
根据以上设计,我们就可以根据 MAIL _STATUS表中的用户ID 、邮件 ID 、邮件状态 Code ,邮箱类型,可以通过联表条件查询获取到收件箱/发件箱对应的邮件分类数据;
-
根据以上设计,我们就可以更好地处理这种一对多关系,比如,1002现在要对邮件 a 进行回执操作,那么我们只需要去修改 MAIL_STATUS 中其(1002)对应的这条状态信息,每个收件人对邮件的处理都是互不影响的;
-
这种设计我们要注意的是,在获取邮件数据的时候需要仔细写正确条件语句,这样才能保证获取到正确的分类数据。
-
-
针对第一章节的第4点,审批功能,因为需求是审批流程通过后收件人才可以收到邮件,因此,我们还需要两种邮件状态:审批未通过、审批通过;接着上述第3点的设计,我们插入一条逻辑:即该邮件审批流程通过后,再去操作第3点所述的针对毎一个收件人分别在 MAIL_STATUS 中插入一条未处理状态( code 为4)的状态记录。
四、总结完整的收发功能逻辑处理过程
- 发送邮件。发件人发送邮件后,存储邮件信息在 MAIL 表中,并针对发件人在 MAIL_STATUS 表中插入一条’发送成功,等待审批’(状态code 为 1)、 邮箱类型为1的状态记录;
- 启动审批流程。本项目使用的是activiti,这里不阐述了;
- 审批邮件。审批时,有两种结果通过不通过,如果审批不通过,则这个结果需要体现在发件人的发件箱里,因此更新对应的状态记录为审批未通过(邮件状态 code 从1变为2);如果审批通过,对于发件人,更新对应的状态记录为"审批通过"(邮件状态 code 从1变为3),此时审批通过后,收件人才能收到邮件,这时对于收件人,需要在收件箱查看到该邮件,因此我们要在 MAIL_STATUS 表中针对该邮件的每一个收件人分别插入一条状态记录为"末处理"(邮件状态 code 为4);
- 查看邮件。这时,使用联表查询,根据相应的条件,分别获取收件箱和发件箱的邮件数据,进行展示;
- 操作邮件。在发件箱中,有已发送和草稿箱两种状态,发件人可以对已发送的邮件进行查看/删除操作、对草稿箱的邮件进行再次编辑并重新发送。在收件箱中,有未处理、已处理等状态,收件人可以对收件箱的邮件行回执/回复/删除等操作,回执有两种结果接受/拒绝,因此我们还需要两种邮件状态:“已处理,接受”( code 为5)和"已处理, 拒绝"( code 为6),收件人进行回执操作后,我们去修改其对应的状态(即状态 code 由4变为5/6)。
五、邮件状态Code
0:保存草稿成功
1:发送成功,等待审批/发送成功
2:审批未通过
3:审批通过
4:未处理
5:已处理,接受
6:已处理,拒绝