权限管理系统 页面权限粒度控制设计 GUID在数据库系统的应用 - Go语言中文社区

权限管理系统 页面权限粒度控制设计 GUID在数据库系统的应用


转自 http://www.cnblogs.com/zyx_blog/articles/2365967.html

系统页面权限粒度控制设计

系统页面权限粒度控制设计

 

说明:

表说明

  • Users 用户表
  • Depts部门表
  • Roles角色表
  • Menus菜单表
  • Pages系统页面
  • Actions各个页面中的操作权限和菜单操作权限
  • RelationUser_Role用户与角色的关系表
  • RelationRole_Action 角色与操作的关系表
  • RelationUser_Action 用户与操作的关系
  • RelationDept_Action部门与操作的关系

权限业务

  • 默认用户只能拥有角色,通过角色获得操作权限.
  • 但是在实际应用中部门,用户都可以具备特殊的操作权限.
  • 此设计即可实现用户通过角色,部门,本身获得操作权限.

解决方式

通过获取3张权限关系表中数据,最后合并权限,即是当前用户所具备的系统操作权限和菜单操作权限

 

图1



GUID在数据库系统的应用

 What‘s GUID ?

    GUID 是个根据网络卡MAC Address 及时间等因素随机产生的 128 Bits(=16 Bytes) 数字, 因为 2 的128 次方是个极大的数目, 因此发生重复的机率非常非常.... 低 (乐观地说: 乐透中奖的机率远远高于 GUID 重复, 我们可以假设 "不可能" 发生)!

    摘录几个网络上流传的例子来说明 GUID 如何地"不太可能" 发生重复:

    一. The probability of an accidental match is (theoretically - and I use that term guardedly) the same as throwing a set of 128 pennies,   and having them all land in the same heads/tails combination twice.
    (把128 个硬币往上拋出落地后, 所有硬币必须出现两次完全相同 "人头" 与 "数字" 的组合)

    二. 如果一台机器每秒钟产生10,000,000 个GUID, 则可以保证(机率意义上) 3,240 年不会发生重复!

    三. 全世界有60 亿人口, 每个人每秒分配10 亿个号码, 那么需要分配1800 亿年! 反正等到地球毁灭了都不会用完的!

    把 GUID 以字符串形式表达就会像 "12345678-1234-1234-1234-123456789012" (4 Bits 代表一个字符, 则有32 个字符, 加上4 条短线共有36 个字符的长度)!

    The challenges of designing database.

    在传统信息系统的数据库端普遍存在几个设计上的难题, 为了解决这些题目, 开发团队经常需要付出较高代价! 这些难题包括:

    一. ID (在此指概指在资料表中用来代表资料唯一性的字段) 值是否允许变更(例如: 部门编号, 产品编号, .....) ? ID 字段总是被使用与其它资料表关联, 因此, 需要先判断关联是否已经存在, 以做为 ID 字段可否变更的依据! 当 ID 字段关联的对象数目过多时, 需要在判断上付出更多成本!

    二. 由复合字段形成资料表关联时, 是否需要对更多字段进行变更前的判断或处理? 

    复合字段组成索引的典型之一是单据明细 (或称 "分录", 或指 Detail data, 其主索引可能由单据编号及明细序号(流水号) 组成)! 当某笔明细资料前方插入或是删除另一笔明细时, 原有的明细序号是否需要变更? 不变更时明细序号是否连号且不重复? 变更后是否会破坏原有与其它资料的关联? 
这可能是个取舍两难的问题: 由于明细资料前方插入或删除另一笔明细资料时, 在后方的所有明细资料的序号 "被迫" 递增或递减 (就像棒球在满垒状况下, 触身球会造成三垒跑者被 "强迫" 挤回本垒得分), 则索引值会发生变化, 而系于该索引上的关联就会错乱!

    三. 无 ID 或主索引字段的资料, 能否与其它资料建立关联?

    在自然情况下有些资料并不需要 ID 字段 (或是 ID 字段值并无实质意义), 例如: 

    1. 每天例行发出的提醒信息可能并不需要 ID 值, 但是, 当使用者从清单中选择一笔资料时, 系统如何明确地找到被指定的提醒明细呢?

    2. 展开MPS 是一个批次作业, 其过程中会有许多的记录临时被产生或是合并!在每一笔过渡记录产生时, 并不需要具有编码规则的 ID 字段, 但是在整合同料号同时段的生产需求时, 如何能够正确地标记已被合并的数据呢?归纳以上的难题, 我们可以发现需求的核心就是: 能否为数据库里的所有记录, 赋予一个: (1)简单, (2)独一无二, (3)不会改变的"身份识别"?

    How does GUID change the world ?

    GUID 的唯一性完全满足我们的需求, 因此, 我们可以一个 GUID 字段做为代理键, 以取代自然键 (通常为资料表中"ID" 字段, 或是复合字段组成的主要索引), 并化解实务上遭遇的问题:

    一. GUID 隔离了自然键以及关联的资料表:

    自然键是可以被检视的, 若自然键为ForeignKey 且有对应的关联资料, 为了保持资料的一致性, 自然键值不应被异动或删除! 这样的保护控制大都需要额外的程序代码去处理!

    代理键通常并不具字面上的意涵(例如: GUID), 因此, 在检视资料时并不会显现该字段, 所以代理键在产生后, 该值并无机会发生改变! 以代理键替代自然键成为资料表关联的主角, 自然键相对地成为类似"备忘" 性质的字段! 由于代理键被隐藏而不会被变更, 不论自然键如何修改, 根源于代理键所形成的数据关联永远稳定地存在!

    二. GUID 替代复合字段的自然主键:

    当自然主键是由多个字段组合而成时, 要撰写资料关联的SQL command 就显得有点烦人! 运用 GUID 字段进行关联, 可以轻易地使 SQL 化繁为简!另外, 当自然键由复合字段组成时, 有更多字段被同时使用于资料关联, 相对地, 需要对字段组合进行更多判断或是限制变更! 这样的控制需要付出偏高的代价, 实务上, 也不尽然可以进行控制, 例如: 因为其它单据明细的增减, 会 "强迫" 部份单据明细自然键里的序号字段递增/ 递减!

    若以 GUID 做为代理键担任资料表的关联角色, 单据明细的 "序号" 字段因不涉及关联, 即可依据实务上的需求被变更, 并不需要额外的判断或控制!

    三. 无自然键的资料表由 GUID 代理主键的功能:

    在无自然主键的资料表建立 GUID 代理键后, 每一笔记录即刻具备可供识别 "身份" 的信息! 即使后来因为需求变更而必须存取该资料表中特定的记录时, GUID 代理键的存在足以满足这类的变动 (类似 "防震" 效果)!


The actual usage of GUID

    一. 在多对多的关联里替代复合字段以简化对应:

    如: 传票分录的立冲 (传票明细多对多立冲), 借还款的冲销 (多对多冲销), ..... 等, 可由 GUID 代理键进行关联, 即可依 GUID 合并后统计冲销金额!

    二. 在临时产生的资料中提供精确的识别:

    如: 有些复杂报表需要额外统计或运算, 当这些运算不需以程序代码循环处理, 即可以SQL command 直接在该报表的暂存数据表批次运算(其实多数报表均为如此)!当多人同时检视相同报表 (检视条件并不相同), 即可运用 GUID 做为该暂存资料表中的识别! 每个使用者每次检视报表即为一个 Task (TaskGUID), 报表运算后只回传 TaskGUID 相符的数据!

    几种高阶的开发语言 (包括: .NET, VB, Delphi, PowerBuilder, ....) 均已包装或是实现呼叫 Windows API 以产生 GUID 字符串的方法了, 所以这个 GUID 值可以由程序代码自行产生!Microsoft SQLServer 也提供了取得 GUID 字符串的函式 NewID; 还有未公开的 Stored procedure: sp_MSforeachtable, 它可以对数据库中所有的资料表进行统一的操作!结合 sp_MSforeachtable 与 NewID, 我们可以在几秒钟内对所有资料表统一添加名为 "GUID" 的字段(实例如下), 开始让 GUID 做为资料搜寻或关联的根据!

    /* 先指定要添加 GUID 字段的数据库后, 直接执行下列语法 */
    sp_MSforeachtable @command1=‘ALTER TABLE ? ADD [GUID] VarChar(36) NOT NULL 
                                               Constraint [?_DF_GUID] DEFAULT (newid()) 
                                               Constraint [?_IX_GUID] UNIQUE NonClustered‘

    What‘s matter with GUID?

    由于做为索引字段(不论是Clustered Index/ Nonclustered Index) 的GUID 长度为36 Bytes, 相较于其它的自然键或自动编号(整数) 均显得过长, 使得索引页可容纳的信息较少, 必须搜寻较多的索引页次才能查询所需要的结果, 因此, 各个网络讨论区对于 GUID 在效能方面的表现是颇有质疑的!不过, 数据库系统的效能包括许多因素, 包括: 系统设计理念, 资料表切割, 索引设定, SQL command 撰写, 内存配置, IO 设备, ..... 等 (排行愈前者影响愈大), 效能调整需要全面的协调与改善, GUID 不会是运行效能的瓶颈肇因!市场上已存在着全面运用 GUID 代理键的商用软件, 被中小企业广泛采用的 Microsoft.SharePoint 系统也是如此!

    由于运用 GUID 做为代理键, 许多因为自然键直接关联的难题会因为 GUID 的隔离而被优雅地化解, 原自然键上的复杂控制均可省略, 资料表之间的关联变得单纯, 数据库系统的运作也更稳定! 


GUID(Global unique identifier)全局唯一标识符,它是由网卡上的标识数字(每个网卡都有唯一的标识号)以及 CPU 时钟的唯一数字生成的的一个 16 字节的二进制值。

GUID 的格式为“xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”,其中每个 x 是 0-9 或 a-f 范围内的一个十六进制的数字。例如:6F9619FF-8B86-D011-B42D-00C04FC964FF 即为有效的 GUID 值。
世界上的任何两台计算机都不会生成重复的 GUID 值。GUID 主要用于在拥有多个节点、多台计算机的网络或系统中,分配必须具有唯一性的标识符。在 Windows 平台上,GUID 应用非常广泛:注册表、类及接口标识、数据库、甚至自动生成的机器名、目录名等。
在这次开发 ASP.NET 应用时,我大量使用了类型为 GUID 的 ID 列作为各实体表的关键字(键)。由于其唯一、易产生的特性,给应用程序处理带来诸多好处。
1、在 SQL Server 中使用 GUID
如果在 SQL Server 的表定义中将列类型指定为 uniqueidentifier,则列的值就为 GUID 类型。
SQL Server 中的 NewID() 函数可以产生 GUID 唯一值,使用此函数的几种方式如下:
1) 作为列默认值
将 uniqueidentifier 的列的默认值设为 NewID(),这样当新行插入表中时,会自动生成此列 GUID 值。

2)使用 T-SQL
在 T-SQL 中使用 NewID()函数,如“INSERT INTO Table(ID,... ) VALUES(NewID(),...)”来生成此列的 GUID 值。
3)提前获取 GUID 值
由于特殊功能需要,需要预先获知新行的 ID 值,也可以使用如下 C# 代码提前获得 GUID 的值,再存储到数据库中:
 SqlCommand cmd = New SqlCommand();
 cmd.CommandText = "SELECT NewID()";
 string rowID = (string) cmd.ExecuteScalar();
 cmd.CommandText = "INSERT INTO Table(ID,...) VALUES(@ID,...)
 cmd.Parameters.Add("@ID",SqlDbType.UniqueIdentifier).Value = new Guid(rowID);
 cmd.ExecuteNoQuery();
uniqueidentifier 值不能进行算术运算,但可以进行(意义不大的)比较操作和 NULL 检查;它不能象 IDENTITY 列一样,可以获知每行的增加时间的先后顺序,只能通过增加其它时间或时间戳列来完成此功能。
2、在 .NET 中使用 GUID
GUID 在 .NET 中使用非常广泛,而且 .NET Framework 提供了专门 Guid 基础结构。
Guid 结构的常用法包括:
1) Guid.NewGUID()
生成一个新的 GUID 唯一值
2) Guid.ToString()
将 GUID 值转换成字符串,便于处理
3)构造函数 Guid(string)
由 string 生成 Guid 结构,其中string 可以为大写,也可以为小写,可以包含两端的定界符“{}”或“()”,甚至可以省略中间的“-”,Guid 结构的构造函数有很多,其它构造用法并不常用。
同时,为了适用数据库中使用 GUID 的需要,.NET Framework 也提供了 SqlGUID 结构,它和 Guid 结构类似,只是两者对排序(CompareTo)的处理方式不同,SqlGuid 计算值的最后 6 个字节。而 Guid 计算全部 16 个字节,这种差异可能会给 SQL Server 中 uniqueidentifier 列的排序带来一定影响,当然这种排序意义也不大。
.NET Framework 中可以使用类 GuidConverter 提供将 Guid 结构与各种其他表示形式相互转换的类型转换器。

3、GUID 的优缺点
1) 优点
  • 同 IDENTITY 列相比,uniqueidentifier 列可以通过 NewID() 函数提前得知新增加的行 ID,为应用程序的后续处理提供了很大方便。

  • 便于数据库移植,其它数据库中并不一定具有 IDENTITY 列,而 Guid 列可以作为字符型列转换到其它数据库中,同时将应用程序中产生的 GUID 值存入数据库,它不会对原有数据带来影响。

  • 便于数据库初始化,如果应用程序要加载一些初始数据, IDENTITY 列的处理方式就比较麻烦,而 uniqueidentifier 列则无需任何处理,直接用 T-SQL 加载即可。

  • 便于对某些对象或常量进行永久标识,如类的 ClassID,对象的实例标识,UDDI 中的联系人、服务接口、tModel标识定义等。
2) 缺点
  • GUID 值较长,不容易记忆和输入,而且这个值是随机、无顺序的,所以使用时要注意场合,最好不要尝试用它来作为你的电子邮件地址 J

  • GUID 的值有 16 个字节,与其它那些诸如 4 字节的整数相比要相对大一些。这意味着如果在数据库中使用 uniqueidentifier 键,可能会带来两方面的消极影响:存储空间增大;索引时间较慢。

综合来说, GUID 的优点带来的便利远超出其缺点带来的影响,随着诸如 WebService 等系统互联与整合技术的不断发展,其唯一标识的特性使得其应用越来越广,在您的应用程序中也应考虑使用它了。

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/wguoyong/article/details/8679408
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2022-12-30 21:25:30
  • 阅读 ( 299 )
  • 分类:Go应用

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢