JSqlParser强大的SQL改写工具-概念
1. 说明
JParser 是一个好用的SQL处理工具,它的强大之处在于可以解析SQL并根据条件随意修改SQL
对于需要某些全局特性的SQL,如添加租户,删除SQL改为逻辑删除、构建动态表等可以实现统一处理,避免业务开发疏忽某些条件参数等。
当然,SQL改写避免不了性能的损耗,它需要解析SQL,修改完成之后再构造SQL,对于高并发场景还是应当慎用
2. 概念
对于JParser来说,我也是一个初学者,现在将一些对于框架的理解分析一下。
2.1. Expression:表达式
大多数方法都是基于它的实现,而且基本上后续大部分的入参都是它,基本属于顶级的存在
2.2. Select 查询
这是对于查询语句的封装,是一个抽象接口,select查询语句就会解析成它。
其实现类有以下集中
- PlainSelect 一般的查询语句
- ParenthesedSelect:带括号的查询语句,一般用于
in
子句中 - WithItem:
with as( )
语句解析成的查询。 - SetOperationList
- TableStatement
- Values
- LateralSubSelect
一般的查询语句基本用其实现PlainSelect
、ParenthesedSelect
这两个类
下面是一个最简单的select查询分解
1 | //使用CCJSqlParserUtil工具解析SQL,这是一个强大的SQL解析器 |
也可以使用
1 |
|
最终都可以得到PlainSelect
,内部方法很多,关于join 、where、 with as 、group by、order by 、limit
等都有,如下示例
1 | select distinct t_u.id u_id,t_r.id r_id |
经过转换得到PlainSelect
对象:
1 | PlainSelect plainSelect = ((Select)CCJSqlParserUtil.parse(sql)).getPlainSelect(); |
可以看出,基本都已经包含了,我们可以直接通过对应的方法拿内部的数据
2.3. Table 表
表字段,就是我们SQL语句中的表相关的封装, 包括from后的主表和join的联表
2.4. ParenthesedSelect 带括号的查询(子查询)
子查询用到的封装,SQL语法中子查询用括号扩起来并在括号后面用表别名命名。
子查询的结果视为一张表,封装之后用ParenthesedSelect
表示
如下:
1 | select * from t_user t_u left join (select * from t_role where id<50) t_r where t_u.id=t_r.user_id |
(select * from t_role where id<50) t_r
即封装成一个ParenthesedSelect
2.5. SelectItem 查询的字段
select查询中最后提取的字段的封装,把所有的返回字段封装成一个列表,每一个对象为一个SelectItem
如SQL:
1 | select id,name from t_user |
其中,id和name 会封装成两个SelectItem
2.6. Where 中表达式
where查询全部使用Expression
抽象,因为where中的匹配其实是多样的,包括and or in exists like between...and... = !=
等
常用的表达式封装有
- AndExpression: and连接
- OrExpression: or连接
- InExpression: in连接
- LikeExpression: like连接
- BetweenExpression: between连接
- EqulesTo: 等号连接
- NotEqulesTo: 不等于
一般都会使用left 和 right 两个属性分别存等号左右两侧的封装
表达式封装的left、rigth
属性对应的也是Expression表达式,因为它也可以包含多种类型
- Column: 表字段名,即我们一般说的id=1中id就封装成一个Colume
- StringValue/LongValue:传入的值,即id=1中的1就会封装成一个StringValue或LongValue,根据是字符还是数字来定
- ParenthesedSelect:带括号子查询,一般是in和exists后面使用
JSqlParser巧妙的把这些都封装好了,使用起来就可以根据SQL语句灵活构造
3. JsqlParser 嵌套理解
JsqlParser整体上是一个递归思想的解析流程,select包含了查询的各项数据,其子元素如SelectItem
、Where
中都有可能实现递归操作
where后面的语法其实是一个树形的条件语法封装,如and、or、in等两边入参都是Expression
,而Expression
本身也是这些实现
因此,理论上可以无限递归下去,因此用树形的数据结构可以很好的解释
如下嵌入多层的SQL示例(当然,实际基本不可能这么写):
1 | select * from user |
构造的树形结构如下
如果加上SelectItem
,则不只是where上的分叉,总的来说是满足树形结构的。