有一个代码的设计问题,大佬们帮帮我

52 天前
 tongjiann

简单介绍一下情况。

  1. 我们是用的是 jdk8+mybatis+MybatisPlus+diboot(小众的 MP 的增强,没看见过可忽略)的后端项目
  2. 每个业务表中都有一个 period(会计期间)字段

现在有一个 PM 提了一个很容易理解但是很傻逼的 Feature:

只有管理员开放指定 period 之后,才能对指定 period 的业务表数据进行增删改查(增删改已经做限制,采用下面第二种方法。),否则都不允许(返回空或提示权限不足) 管理员无视上面一条要求

初步想法

  1. 在所有的查询语句执行前在代码层添加可查询的 period 列表。
    • 比如 select * from table a where id = 'xxx',那就改成 select * from table a where id = 'xxx' and period in (valid_period_list);
  2. 对所有的查询出来的数据进行校验。由于增删改单次进行的对象的数据量较小,所以在增删改操作进行前做一次查询取出所有被查询的数据并判断 period ,这样损耗较小,目前可以接受。但是当查询的时候使用系统方法我认为会严重损耗性能。
    • 比如 select * from table a where id = 'xxx'。在查询出数据之后,在代码层进行一次校验,判断 period 是否合理。

请问一下大佬们对这个 Feature 有什么比较好的实现经验吗,或者说比较好的 idea

4863 次点击
所在节点    程序员
43 条回复
cnhongwei
52 天前
用 mybatis 不清楚,用 spring security+spring data jpa 有这个查询增加条件和结果集检查功能,但只是看文档中有,没有实践过,不知道对性能有多少影响。但如果用到 spring security 的话,可以看看 spring security 的文档,在 mybatis 中能不能实现。
Musong
52 天前
我前端啊,后端不懂。有个小小问题,权限是不是应该在查询之前,在代码逻辑中就给拦截了?(我可完全不懂啊,问错了不要笑话我)
billbur
52 天前
第一种就行了,数据库没你想象的那么脆弱,一个是要注意覆盖索引,另一个是分页或者说限制一次能查询的数量
tongjiann
52 天前
@cnhongwei #1 好的,感谢
dong568789
52 天前
我们是加了个 middleware,所有请求经过中间件,都会判断是否要加这个 period 条件判断,如果是就注入到 query 里,然后拼装 sql 的地方,会解析这个 period
tongjiann
52 天前
@Musong #2 你说的没问题,部分请求中存在这个参数,确实可以在查询之前进行拦截。但是吧,有部分情况是,比如和描述中一样,select * from table a where id = 'xxx'。这个时候我并不知道查询出来的数据的 period 是啥。还得查出在之后再进行校验看看是不是合法数据。不过这个方法可行,确实可以加两层,前面先过滤掉一批,这样可以适当的减轻数据库的压力
paopjian
52 天前
我也不懂后端, 这个应该和用户权限校验走一起的逻辑吧, 在用户权限校验处加一个操作权限判断, 这样以后还有其他的新控制字段也可以再加入
tongjiann
52 天前
@paopjian #7 是的,从代码设计上来说没问题。但是我们目前的系统为了偷懒,允许前端通过构建类似于 SQL 查询条件的方式,直接请求通用接口查询数据库中的数据,可以直接跳过对应字段的校验。但是已经是一坨了,只能往上面再来一坨了
leejinhong
52 天前
在代码层加这种判断有点不太好,如果后期继续加权限逻辑岂不是得改很多。如果有使用 ORM 的话,适当改装一下 ORM ,业务层面通过 ORM 操作,对于本来业务的侵入会比较少。
theOneMe
52 天前
1. 逻辑上应该是第一种,第二种的话,分页查询如果查询之后过滤可能出现为空的问题,导致缺页;
2. 数据量如果百万以下,不用考虑太多,直接操作就行
tongjiann
52 天前
@dong568789 #5 这个 idea 很好,和我的第一种想法类似,不过你的可能更加完善。我验证一下这个方法在我们代码中的可行性
tongjiann
52 天前
@leejinhong #9 这个需求是针对系统的需求,和业务无关,最终实现肯定是在一个 ORM 层进行实现,并不是在每个业务实现类中进行操作
2tongW
52 天前
我也做过类似的需求,就是采用的第一种方法。如果担心性能的话,是不是可以考虑新增一个“是否可操作”的字段,来维护。
代价就是管理员开放指定 period 的时候需要去批量更新这个字段。
Jasckcc
52 天前
可考虑使用布隆过滤器或 redis 做前置条件验证。
needpp
52 天前
新建一个 视图 ,在视图里面查询
uselessVisitor
52 天前
Mybatis 插件动态添加 period 字段的筛选
andy2415
52 天前
之前写的<=的逻辑, 只处理了删改查你可以试试改成 in,
```java
@Slf4j
public class Demo extends JsqlParserSupport implements InnerInterceptor {

@Override
public void beforePrepare(
StatementHandler sh, Connection connection, Integer transactionTimeout) {
PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);
MappedStatement ms = mpSh.mappedStatement();
SqlCommandType commandType = ms.getSqlCommandType();

if (commandType == SqlCommandType.SELECT || commandType == SqlCommandType.UPDATE || commandType == SqlCommandType.DELETE) {
mpSh.mPBoundSql().sql(parserMulti(mpSh.mPBoundSql().sql(), null));
}
}

@Override
protected void processSelect(Select select, int index, String sql, Object obj) {
PlainSelect plainSelect = (PlainSelect) select.getSelectBody();
MinorThanEquals minorThanEquals = getMinorThanEquals();
Expression where = plainSelect.getWhere();
plainSelect.setWhere(
where == null ? minorThanEquals : new AndExpression(where, minorThanEquals));
}

@Override
protected void processUpdate(Update update, int index, String sql, Object obj) {
....
}

@Override
protected void processDelete(Delete delete, int index, String sql, Object obj) {
....
}

@NotNull
private static MinorThanEquals getMinorThanEquals() {
MinorThanEquals minorThanEquals = new MinorThanEquals();
minorThanEquals.setLeftExpression(new Column("column_name"));
minorThanEquals.setRightExpression(new LongValue(4));
return minorThanEquals;
}
}
```
28Sv0ngQfIE7Yloe
52 天前
就算是 1 也没必要 select *吧?只要 select count (*)是不是就能满足业务需要了?
andy2415
52 天前
@andy2415 #12 另外, mybatisplus 拦截器初始化顺序要 注意添加再分页的后面, 不然分页查询会有问题
tongjiann
52 天前
@Morii #18 最终的数据要进行后续的操作,如前端展示,那这个时候需要的不只是数据条数了,count 还不够吧

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1060204

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX