简介
日常编写sql语句时, 经常用到变量占位符, 常用的有 ?, @val, #{val}, ${val} 等.
本工具类也支持上述变量占位符, 但与标准写法略有扩充和差异, 在此做专门的说明.
? 预编译占位符
? 占位符用于防注入传参, 仅在 sql 的某些特定位置有效, 标准用法如下:
query("select * from table where a > ?", 1);
query("select * from table where a in (?)", 1);
标准语法在 in 包含多个值时, 无法自适应 ? 占位符的数量. 因此在参数数量可变时, 使用起来很不方便.
本工具类扩展了 ? 的用法, 允许一个 ? 代指多个变量, 用法如下:
List<Integer> list = new ArrayList();
list.add(1);
list.add(2);
query("select * from table where a in (?)", list);
// 上述写法等效于下文
query("select * from table where a in (?, ?)", 1, 2);
此扩展特性适用于所有实现类, 比如 mongo, solr, es, hbase, csv 等.
@val 运行时变量
@val 占位符用于运行时计算的参数, 仅在 sql 的某些特定位置有效, 标准用法如下:
set @a := 1+1; -- 允许运算
select * from table where a = @a
-- 等效于
select * from table where a = 2
标准情况下变量只能是单一值, 无法存储数组.
本工具类扩展了变量的用法, 允许一个变量代指多个值, 用法如下:
set @a@list = [1,2]; -- 此时变量名必须以 @list 结尾
select * from table where a in (@a@list)
-- 上述写法等效于下文
select * from table where a in (1,2)
此特性适用于所有实现类, 比如 mongo, es, hbase 等.
#{val}, ${val} 预处理变量
#{val}, ${val} 占位符在 sql 被执行前替换 sql 的部分内容, 因此可以使用在sql的任何位置.
考虑防注入问题, 本工具类强制限制 #{val}, ${val} 的效果等于 MyBatis 的 #{val} 效果, 也就是任何非纯数字变量被替换时都会加’’. 实际效果如下:
Map<String, Object> param = new HashMap();
param.put("year", 2020); // 数字不会加引号
param.put("type", "2"); // 字符串会加引号
query("select * from table_#{year} where type = #{b}", param);
// 上述写法等效于下文
query("select * from table_2020 where type = '2'");
出于兼容性考虑, 当遇到 ${hiveconf:val} 时, 当作 ${val} 处理.
$${val} 预处理变量
有小伙伴希望保留 MyBatis 的 ${val} 效果, 允许直接替换 sql 内容.
考虑再三, 因为各种原因没敢开放此功能. 但是提供了一个中间方案.
参考的 @@val 作为全局变量的思路, 开放了 $${val} 全局变量, 此变量允许直接替换 sql, 绕过防注入限制, 但是只允许注入全局变量.
- 关于全局变量
本工具包的全局变量无法使用 sql 修改, 必须去数据库中的全局变量表中定义.
首先要注册一个全局变量表, 支持使用 sql 表, mongo 表, List 作为全局变量表的载体.
// 将 ServerSettingDaoListImpl 注入到 ServerSettingUtil;
ServerSettingDaoListImpl.initServerSettingUtil();
// 将 MongoServerSettingDao 注入到 ServerSettingUtil;
// MongoServerSettingDao.initServerSettingUtil(conf);
// 将变量 aaa = test_table 写入全局变量, 也可以手动去数据库中定义全局变量
ServerSettingUtil.setStrValue("code_snippet_aaa", "test_table");
// 执行查询
query("select * from $${aaa} where type = '2'");
// 上述写法等效于下文
query("select * from test_table where type = '2'");