层级系统
2017-10-20 本文已影响57人
JSON_NULL
目标
抽象层级结构,构建统一的层级管理系统。
要解决的问题:
- 系统层级管理困难
- 因系统层级变动所引发的系统重构。
重点
- 可重用,场景的覆盖一定要全面,可适合用于各种各样的场景。
- 可扩展,在应用到不同场景时,可以方便的扩展以支持对应场景的附加要求。
数据表结构
system_level 表
字段:
- level_id,唯一标识,在system_level表中唯一标识一个层级记录。
- level_name,层级名称,需要限制长度。
- level_pid,上级层级记录的唯一标识,记录自己的父层级。
- is_deleted,是否已经删除,如果已经删除则存储一个非0值,为数据安全而做的软删除功能。
表说明:
- system_level 表 负责存储层级结构,所有level_pid为零的记录表示一个顶级,每个顶级下可以扩展多个子层级,子层级还可以继续扩展子层级,如此往复不限制深度。
- level_id做主键,为了提高查询效率还需要对level_name,level_pid,is_deleted分别做索引。
字段说明;
is_deleted,如果记录是正常可用状态,则其值为0。如果是删除状态(软删除)则其中存储的是用户直接操作删除的层级记录的id值。这里需要详细说明一下,在对system_level表中的记录进行删除操作时,需要级联删除其下所有的子层级;如果用户操作删除一个层级,则所有需要删除的层级记录(包含用户直接操作删除的和被级联删除的子层级)的is_deleted字段中都会存储用户直接操作删除的那个层级记录的id值。
system_level_relationship 表
字段:
- level_id,system_leve表中的唯一标识,在这里用于确定一个作为子层级的记录。
- level_ppid,system_level表中的唯一标识,在这里用于确定一个祖先层级的记录。
表说明:
- system_level_relationship表用于记录一个层级的所有祖先。level_id用于确定这里记录的是谁的祖先,level_ppid用于确定祖先是谁。一个记录可以有多个祖先(父、祖父等),一个记录也可以有多个子孙(多个孩子,多个孙子)。
- level_id和level_ppid 做联合主键,为了提高连接查询效率还需要分别对level_id和level_ppid做索引。
应用场景及方案
场景1:
- 层级结构为省、市、县、校,每一个层级下都可以有多个球队(省队、市队、县队、校队)。
- 每个球队下面还可以有教练、球员等。
- 在层级结构中上级可以查看所有直属或非直属下级所有的球队、教练、球员。
方案:
- 使用层级系统中的 system_level 和 system_level_relationship 表。
- 球队表需要有唯一标识squad_id,还需要存储它所属的层级level_id。
- 教练表、球员表需要有自己的唯一标识coach_id、player_id,还需要存储它们所属的球队和层级squad_id和level_id。
- 查询所有下级的球队 select s.* from squad s left join system_level_relationship slr on s.level_id = slr.level_id where slr.ppid = ?
- 查询所有下级的教练 select c.* from coach c left join system_level_relationship slr on c.level_id = slr.level_id where slr.ppid = ?
场景2:
- 在与(场景1)要求相同的情况下增加以下需求。
- 层级结构省、市、县、校要求存储除了名字之外的其他信息
方案:
- 增加一张省表province,需要level_id字段记录省所属的层级,同时用level_id做主键。
- 增加一张市表city,用level_id记录其所属的层级、同时也用level_id做主键。
- 增加一张县表county,用level_id记录所属的层级,同时也用level_id做主键。
- 增加一张学校表club,也用类似上面(1、2、3)中的处理方式。
- 针对(1,2,3,4)中的表进行分析,如果有结构相同或相似的表则可以进行合并。
场景3:
- 在与(场景2) 要求相同的情况下增加以下需求。
- 在查看教练、球员时,需要附带其所属层级(省、市、县、校)的详细信息,不仅仅是名称还需要在附加表(provicen/city/county/club)中的信息。
场景分析:
在(场景2)的方案中,从教练、球员可以得到其所属的层级,但从层级记录中无法确定其类型(省、市、县、校)。因为不同的类型对应着不同的详细信息表,所以在知道层级而不知识其类型时,是无法确定详细信息是在哪张表中存储着的。
方案一:
在system_level中添加一个level_type字段,用于记录该层级的类型,从而确定详细信息在哪一张表中。
方案二:
新增一张表system_level_meta(level_id,level_key,level_value),通过level_id和level_key='type'时的level_value值来确定层的类型,从而确定详细信息在哪一张表中。
方案比较:
- 方案一需要改动原设计中的表,且只能解决当前问题;方案二不影响原设计中的表,除解决当前问题外,还对以后的扩展留有可扩展的灵活性。
- 方案二因需要增加表而增加了系统的复杂度,方案一只是中一个字段相对来说因变更而增加的系统复杂度较小。