数据权案例
mybatis 的 sql 构造,可能是我们程序猿每天都需经历的过程,前几天公司有了一个新的需求,做一个表结果的数据权限。
举个栗子:
某张表中维护这大量的客户信息,但是客户信息不是每个用户都看到,系统中维护一个树形结果的组结构,根据上下级的关系进行数据查看权限。
A
a1
a2
a1,a2只能看到自己维护的信息。
A可以看到自己以及a1,a2以及自己信息。
其实这个问题从最开始分析的话,其实是可以在先将所有的数据查询先查询出来在进行处理,但是一般进行数据查询的时候,都是分页查询,这样的话一定会然查询出来数据和进行过滤出来的数据有区分,可能分页是查询 10 条 ,结果在过滤下没有 10 条数据,而且就在进行其他处理达到效果,但是在效率上是一定会有很大的影响的。
出发点只能走--sql 构造数据权限
思路设计:我只需要查询出来的表的某个字段,或者关联其他表某个字段匹配到某个用户权限集合就可以了
select *from customer cus
left join user use on use.id = cus.createuser
where cus.createuser in (.....所需要的数据权限)
- 第一步
如何获取都某张表的所有集合,我们可以使用 mysql 的函数来进行构造出我们需要的数据,直接上脚本
CREATE DEFINER=`root`@`%` FUNCTION `getTableChildList`(rootId varchar(100)) RETURNS varchar(2000) CHARSET utf8
BEGIN
DECLARE str varchar(2000);
DECLARE cid varchar(2000);
SET str = '';
SET cid = rootId;
SET str = concat(str, ',', cid);
SELECT group_concat(id) INTO cid FROM team where FIND_IN_SET(parent_id, cid) > 0;
RETURN str;
END
解释:team 是小组的表名 根据 id 找打它的 parent_id 的所对应的 id ,直至下级全部查询完毕!
1.表 名team 团队名称 --包含 了一个
leaderid 组长id
parent_Id 上级团队
2.表 名 member 团队成员
memberid 成员id
salesteamid 团队主键
这个函数可以写的更加适配一些,可以供应多个表结构使用。上代码
CREATE DEFINER=`root`@`%` FUNCTION `getTableChildList`( tablename varchar(100) ,rootId varchar(100)) RETURNS varchar(2000) CHARSET utf8
BEGIN
DECLARE str varchar(2000);
DECLARE cid varchar(2000);
SET str = '';
SET cid = rootId;
IF tablename ='A' then
WHILE cid is not null DO
SET str = concat(str, ',', cid);
SELECT group_concat(id) INTO cid FROM A where FIND_IN_SET(parent_id, cid) > 0;
END WHILE;
ELSEIF tablename ='B' THEN
WHILE cid is not null DO
SET str = concat(str, ',', cid);
SELECT group_concat(id) INTO cid FROM B where FIND_IN_SET(parent_id, cid) > 0;
END WHILE;
ELSEIF tablename ='C' THEN
WHILE cid is not null DO
SET str = concat(str, ',', cid);
SELECT group_concat(id) INTO cid FROM C where FIND_IN_SET(parentid, cid) > 0;
END WHILE;
END IF;
RETURN str;
END
将函数脚本中,就可以实现我们需要的效果了 ,这里默认#{parameter.condition.loginUserId}是一定有值的,如果是自己卸载 mapper.xml 文件中话,要加上 if 判断操作。
SELECT
*
FROM
customer cus
LEFT JOIN USER USE ON USE.id = cus.createuser
WHERE 1=1
<if test="parameter.condition != null and parameter.condition.loginUserId !=null and parameter.condition.loginUserId !='' ">
and
cus.createuser IN (
SELECT DISTINCT
memberid
FROM
member
WHERE
salesteamid IN ( SELECT id FROM team WHERE FIND_IN_SET( id, getTableChildList (
'team', ( SELECT id FROM team WHERE leaderid = #{parameter.condition.loginUserId} ) )
) )
)
</if>
注意这样的写法还会存一个问题,如果我查询的一个人是组长,而且刚好我的下级没有了组员,为了系统的效率问题,可以加上一个 if 的语句进行判断
语法规则:IF(boolean condition,"true","false");
改进版效率提升,而且扩展性更好。
SELECT
*
FROM
customer cus
LEFT JOIN USER USE ON USE.id = cus.createuser
WHERE 1=1
<if test="parameter.condition != null and parameter.condition.loginUserId !=null and parameter.condition.loginUserId !='' ">
AND IF
(
(
SELECT
count( id )
FROM
team
WHERE
FIND_IN_SET( id, getTableChildList ( 'team', ( SELECT id FROM team WHERE leaderid =
#{parameter.condition.loginUserId} ) ) )
) > 0,
cus.createuser IN (
SELECT DISTINCT
memberid
FROM
member
WHERE
salesteamid IN ( SELECT id FROM team WHERE FIND_IN_SET( id, getTableChildList (
'team', ( SELECT id FROM team WHERE leaderid = #{parameter.condition.loginUserId} ) )
) )
)
,
cus.createuser IN ( SELECT DISTINCT memberid FROM member WHERE memberid =
#{parameter.condition.loginUserId} )
)
</if>
扩展
- IFNULL("t1","t2")【mysql】
- ISNULL("t1","t2")【SQL Server / MS Access】
- NVL("t1","t2")【Oracle】
第一参数如果为 null 使用第二个参数
- IF(boolean condition,"true","false");
第一个参数布尔判断和为 true ,使用第二个参数,false 使用第三个 参数;和三目运算的规则一样。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于