系统权限数据库设计方案

一、问题描述

       目前基本上的系统都会涉及到权限的控制,而且粒度都比较小,一般都要控制到具体窗口的具体操作上。而要达到这种要求,一个可行的数据库设计将显得非常有帮助。下面我们就设计一个通用型的数据库来达到权限的控制

二、测试环境

       操作系统:windows xp

       数据库:mysql5.0

       辅助设计工具:PowerDesigner15

三、设计过程

       1、利用PowerDesigner设计出需要的表,如下图

       2、导出sql脚本,如下

/*==============================================================*/
/* DBMS name:      MySQL 5.0                                    */
/* Created on:     2013-1-25 11:19:43                           */
/*==============================================================*/


drop table if exists T_MENU;

drop table if exists T_MENU_PRIVILEGE;

drop table if exists T_PRIVILEGE;

drop table if exists T_ROLE;

drop table if exists T_USER;

drop table if exists T_USER_ROLE;

/*==============================================================*/
/* Table: T_MENU                                                */
/*==============================================================*/
create table T_MENU
(
   MENUID               int(4) not null auto_increment,
   NAME                 varchar(50),
   URL                  varchar(100) comment '目标网址',
   PARENTID             bigint comment '父菜单',
   LFT                  int(4) comment '左边界',
   RGT                  int(4) comment '右边界',
   primary key (MENUID)
);

alter table T_MENU comment '菜单表';

/*==============================================================*/
/* Table: T_MENU_PRIVILEGE                                      */
/*==============================================================*/
create table T_MENU_PRIVILEGE
(
   MENU_PRIVILEGE_ID    bigint not null auto_increment,
   MENUID               int(4),
   PRIVILEGEID          int(3),
   ROLEID               int(3),
   primary key (MENU_PRIVILEGE_ID)
);

alter table T_MENU_PRIVILEGE comment '角色菜单权限表';

/*==============================================================*/
/* Table: T_PRIVILEGE                                           */
/*==============================================================*/
create table T_PRIVILEGE
(
   PRIVILEGEID          int(3) not null auto_increment,
   NAME                 varchar(50) comment '权限名称(增加,删除……)',
   primary key (PRIVILEGEID)
);

alter table T_PRIVILEGE comment '权限表';

/*==============================================================*/
/* Table: T_ROLE                                                */
/*==============================================================*/
create table T_ROLE
(
   ROLEID               int(3) not null auto_increment,
   ROLENAME             varchar(20) comment '角色名称',
   primary key (ROLEID)
);

alter table T_ROLE comment '角色表';

/*==============================================================*/
/* Table: T_USER                                                */
/*==============================================================*/
create table T_USER
(
   USERID               bigint not null auto_increment,
   USERNAME             varchar(50),
   PASSWORD             varchar(20),
   primary key (USERID)
);

alter table T_USER comment '用户表';

/*==============================================================*/
/* Table: T_USER_ROLE                                           */
/*==============================================================*/
create table T_USER_ROLE
(
   USER_ROLE_ID         bigint not null auto_increment,
   USERID               bigint,
   ROLEID               int(3),
   primary key (USER_ROLE_ID)
);

alter table T_USER_ROLE comment '用户角色';

alter table T_MENU_PRIVILEGE add constraint FK_Reference_3 foreign key (MENUID)
      references T_MENU (MENUID) on delete restrict on update restrict;

alter table T_MENU_PRIVILEGE add constraint FK_Reference_4 foreign key (ROLEID)
      references T_ROLE (ROLEID) on delete restrict on update restrict;

alter table T_MENU_PRIVILEGE add constraint FK_Reference_5 foreign key (PRIVILEGEID)
      references T_PRIVILEGE (PRIVILEGEID) on delete restrict on update restrict;

alter table T_USER_ROLE add constraint FK_Reference_1 foreign key (USERID)
      references T_USER (USERID) on delete restrict on update restrict;

alter table T_USER_ROLE add constraint FK_Reference_2 foreign key (ROLEID)
      references T_ROLE (ROLEID) on delete restrict on update restrict;


从脚本中可以清晰的看出每个表和字段的作用及数据类型,这里面着重要理解的是menu数据表中的左右边界问题,可以结合下面的图进行理解

3、对于菜单的操作,我们开发以下几个存储过程来进行操作

       1)添加子菜单AddChildMenu,每次添加的子菜单都在最前面,如果需要添加到后面,则可以采用下面的AppendMenu来实现,代码如下

CREATE DEFINER=`root`@`localhost` PROCEDURE `AddChildMenu`(
       IN P_PARENTID int(11),
       IN P_MENUNAME VARCHAR(50),
       IN P_MENUURL VARCHAR(100))
BEGIN
     DECLARE VAL_LFT INT(4);
     -- 获取父菜单的lft值
     SELECT LFT INTO VAL_LFT FROM T_MENU WHERE MENUID=P_PARENTID;
     -- 将所有rgt大于当前父菜单lft值的菜单的rgt+2
     UPDATE T_MENU SET RGT=RGT+2 WHERE RGT>VAL_LFT;
     -- 将所有lft大于当前父菜单lft值的菜单的lft+2
     UPDATE T_MENU SET LFT=LFT+2 WHERE LFT>VAL_LFT;
     -- 插入新的子菜单lft=lft+1,rgt=lft+2
     INSERT INTO T_MENU(NAME,URL,PARENTID,LFT,RGT) VALUES(P_MENUNAME,P_MENUURL,P_PARENTID,VAL_LFT+1,VAL_LFT+2);
     -- 显示结果
     SELECT * FROM T_MENU;
END;


调用示例 CALL AddChildMenu(1,'用户管理',');

       2)、附加菜单AppendMenu,将菜单附加都某个菜单的后面,代码如下

CREATE DEFINER=`root`@`localhost` PROCEDURE `AppendMenu`(
       IN P_MENUID int(11),
       IN P_MENUNAME VARCHAR(50),
       IN P_MENUURL VARCHAR(100))
BEGIN
     DECLARE VAL_RGT INT(4);
     DECLARE VAL_PARENTID INT(11);
     -- 获取当前菜单的rgt值
     SELECT RGT,PARENTID INTO VAL_RGT,VAL_PARENTID FROM T_MENU WHERE MENUID=P_MENUID;
     -- 将所有rgt大于当前菜单rgt值的菜单的rgt+2
     UPDATE T_MENU SET RGT=RGT+2 WHERE RGT>VAL_RGT;
     -- 将所有lft大于当前菜单rgt值的菜单的lft+2
     UPDATE T_MENU SET LFT=LFT+2 WHERE LFT>VAL_RGT;
     -- 插入新的菜单lft=rgt+1,rgt=rgt+2
     INSERT INTO T_MENU(NAME,URL,PARENTID,LFT,RGT) VALUES(P_MENUNAME,P_MENUURL,VAL_PARENTID,VAL_RGT+1,VAL_RGT+2);
     -- 显示结果
     SELECT * FROM T_MENU;
END;


调用示例,CALL AppendMenu(2,'角色管理','');

       3)、删除菜单DelMenu,代码如下

CREATE DEFINER=`root`@`localhost` PROCEDURE `DelMenu`(
       IN P_MENUID int(11)
       )
BEGIN
     DECLARE VAL_LFT INT(4);
     DECLARE VAL_RGT INT(4);
     DECLARE VAL_WIDTH INT(4);
     -- 获取当前菜单的lft和rgt值
     SELECT LFT,RGT INTO VAL_LFT,VAL_RGT FROM T_MENU WHERE MENUID=P_MENUID;
     SET VAL_WIDTH=VAL_RGT-VAL_LFT+1;
     -- 删除lft到rgt之间的菜单
     DELETE FROM T_MENU WHERE LFT BETWEEN VAL_LFT AND VAL_RGT;
     -- 将所有的右边界大于第一步中得到的rgt的所有节点的rgt的值减去第一步中得到的宽度width
     UPDATE T_MENU SET RGT=RGT-VAL_WIDTH WHERE RGT>VAL_RGT;
     -- 将所有的左边界大于第一步中得到的rgt的所有节点的lft的值减去第一步中得到的宽度width
     UPDATE T_MENU SET LFT=LFT-VAL_WIDTH WHERE LFT>VAL_RGT;
     -- 显示结果
     SELECT * FROM T_MENU;
END;


调用示例 CALL DelMenu(2);

       4)、每个存储过程的实现和算法具体参考代码注释

4、测试结果

       1)、在执行过插入菜单操作后的数据如下

       2)、利用sql语句查询出所有菜单及其层次关系,代码如下

SELECT MENU.MENUID,
       MENU.PARENTID,
       MENU.NAME,
       MENU.URL,
       MENU.LFT,
       MENU.RGT,
       COUNT(PARENT.MENUID) MENULEVEL
FROM T_MENU MENU,T_MENU PARENT
WHERE MENU.LFT BETWEEN PARENT.LFT AND PARENT.RGT
GROUP BY MENU.MENUID,MENU.PARENTID,MENU.NAME,MENU.URL,MENU.LFT,MENU.RGT
ORDER BY MENULEVEL
       


结果如下

你可能感兴趣的:(solution,database)