请教一个 SQL 改写问题

2023-02-13 14:52:54 +08:00
 Wh1te
背景:用户表目前明文存储着用户的姓名、手机号等等,现在需要改为密文存储。

方案:使用 mybatis 的插件功能,修改参数,将需要加密的字段加密后再执行。上线后清洗数据,将历史明文数据刷为密文。

问题:历史数据量比较大,在刷数据时存在这样一段过度时期是明文和密文同时存在的(旧数据是明文,新写入的数据是密文),手机号在业务上又是有精确查询的需求,很多 SQL 都有 mobile = 'xxxxxx' 的查询条件,在过度时期也要保证这些 SQL 能查到正确的数据,目前想到的办法是用 mybatis 的插件修改 SQL ,将 mobile = '明文' 改写成 mobile in ('明文', '密文'),等过渡时期结束后再去掉这个插件。那么问题来了,这样的 SQL 改写需求有没有什么方便快捷的实现方案呢?
1672 次点击
所在节点    Java
16 条回复
ProgrammerAlan
2023-02-13 15:51:17 +08:00
public class CustomSQLInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
BoundSql boundSql = statementHandler.getBoundSql();
String sql = boundSql.getSql();

if (sql.contains("mobile =")) {
// 对 SQL 进行修改
sql = sql.replace("mobile =", "mobile in");
sql = sql.replace("'", "('");
sql = sql + "', '密文')";

// 使用新的 SQL
Field field = boundSql.getClass().getDeclaredField("sql");
field.setAccessible(true);
field.set(boundSql, sql);
}

return invocation.proceed();
}

@Override
public Object plugin(Object target) {
if (target instanceof StatementHandler) {
return Plugin.wrap(target, this);
}
return target;
}

@Override
public void setProperties(Properties properties) {
}
}
ProgrammerAlan
2023-02-13 15:54:29 +08:00
@ProgrammerAlan ChatGPT 给出的答案,使用 Mybatis 拦截器改写 SQL
paopjian
2023-02-13 16:00:35 +08:00
为什么不新建一张表,新数据放新表,旧数据修改好后再放新表里,最后删除?
jomalonejia
2023-02-13 16:09:01 +08:00
新字段 or 新表 先保证库里有数据 再调整业务逻辑 over
blubzz
2023-02-13 16:18:00 +08:00
建议表新增加密字段,代码增加双写逻辑,同时保存明文和密文,但查询逻辑还是用明文字段。
然后历史数据加密跑批,最后再切换使用密文查询。
sxfscool
2023-02-13 16:23:41 +08:00
加新字段吧
Wh1te
2023-02-13 17:59:53 +08:00
@paopjian #3
@jomalonejia #4
@blubzz #5
@sxfscool #6

实际需求有几十个表,几十个字段,而且历史数据量比较大,感觉加新表新字段做起来也挺麻烦的😂
Wh1te
2023-02-13 18:00:40 +08:00
@ProgrammerAlan #1 这个直接字符串替换感觉不太行,如果 SQL 有个换行或者用了别名联表啥的,就 GG 了
heysnakelis
2023-02-13 18:06:35 +08:00
根据手机号码的最后一个数字 逐步清洗,先清尾号 1 的数据,然后写 sql 的时候如果尾号 1 就走加密查询,尾号不是就原手机号查询,分配清洗替换?
season8
2023-02-13 18:20:46 +08:00
如你所说,就一个用户表需要加密,那代码量应该不多吧,硬改工作量应该还好,就硬改呗。
Wh1te
2023-02-13 18:43:00 +08:00
@season8 #10 不好意思,主贴没有写清楚,只是拿一个用户表举例,实际需求是有几十表存在这样的数据需要处理😧
dog82
2023-02-14 10:46:26 +08:00
2 楼说的用拦截器是个好思路,就是不知道拦截规则怎么定义
Wh1te
2023-02-15 22:38:35 +08:00
@dog82 #12 是的,我说的 mybatis 插件就是 mybatis 的拦截器,我想问的是这个 SQL 改写逻辑要怎么实现
echoless
2023-02-18 16:08:54 +08:00
@Wh1te 手机号在业务上又是有精确查询的需求,很多 SQL 都有 mobile = 'xxxxxx' 的查询条件

`
where mobile = encrypt_mobile('xxxxxx')

encrypt_mobile 是个 function 写到 database 里面, 或者利用 database 已有的函数.
`
echoless
2023-02-18 16:14:13 +08:00
上面的作废, 没读完.

sql 改写 如果你通过的是 orm 可以在 orm 层做. 该 raw sql, 可以解析 sql, 找到有 mobile 筛选条件, 去替换. (如果 sql 不多, 人工更简单吧)
Wh1te
2023-02-19 12:46:44 +08:00
@wuhaoecho #15 改 raw sql, 可以解析 sql, 找到有 mobile 筛选条件, 去替换.
我的主要问题就是这个实现的代码写不出来 😂

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

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

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

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

© 2021 V2EX