Foxnic-SQL (2) —— SQL表达式(Expr)
常规意义的表达式
表达式是运算符、常量和变量的组合。一个表达式可以由一个或多个操作数和零个或多个运算符组成以产生一个值。常量表达式、数学运算、关系表达式、逻辑表达式、位表达式等。
SQL表达式
Foxnic-SQL 中所说的表达式,其实是SQL表达式。任何带有变量占位符的字符串就是一个SQL表达式,这些表达式最终可以拼装成一个完整的SQL语句。Foxnic-SQL 支持命名占位符(:NAME)和匿名占位符(?)。Foxnic-SQL 通过 Expr 类构建与解析SQL表达式,例如:
Expr expr1=new Expr("select ?+? as result from dual",8,9);
System.out.println("expr1 = "+expr1);
// 输出:expr1 = select 8 + 9 as result from dual
这样一个查询语句就是一个表达式,其中的问号(?)就是变量占位符,他们没有名称只有顺序,所以是匿名占位符。
Map<String,Object> namedParam=new HashMap<>();
namedParam.put("P1",18);
namedParam.put("P2",19);
Expr expr2=new Expr("select :P1+:P2 as result from dual",namedParam);
System.out.println("expr2 = "+expr2);
// 输出:expr2 = select 18 + 19 as result from dual
本示例将原来的问号(?)占位符换成了以冒号(:)开头的有名称的占位符P1、P2,这就是带有命名占位符的SQL表达式。当然表达式还可以更为简单,例如:
Expr expr1=new Expr("age>?",28);
System.out.println("expr1 = "+expr1);
// 输出:expr1 = age> 28
也可以是:
Expr expr1=new Expr("age>? and height>?",28,182);
System.out.println("expr1 = "+expr1);
// 输出:expr1 = age> 28 and height> 182
就技术角度而言,SQL表达式所关心的核心问题是变量占位符,至于内容是否符合SQL语法,它并不关心。
SQL表达式的执行
当一个SQL表达式完整且符合SQL语法时,它就可以被数据库执行。表达式通过DAO传递给JDBC执行时,这些占位符被解析并处理成绑定变量。当表达式被打印或输出时,占位符会被处理成符合指定数据库语法且变量已代入的SQL字符串。
/**
* 2、表达式通过DAO传递给JDBC执行时,这些占位符被解析并处理成绑定变量。当表达式被打印或输出时,占位符会被处理成符合指定数据库语法且变量已代入的SQL字符串。
* */
public static void demo2() {
Date date= DateUtil.parse("2022-12-05");
Expr expr1=new Expr("select ?+? as result from my_table where create_date>?",8,9,date);
System.out.println("传递给JDBC的语句(匿名占位符) = "+expr1.getListParameterSQL());
// 输出:传递给JDBC的语句(匿名占位符) = select ? + ? as result from my_table where create_date> ?
System.out.println("传递给JDBC的语句(命名占位符) = "+expr1.getNamedParameterSQL());
// 输出:传递给JDBC的语句(命名占位符) = select :PARAM_1 + :PARAM_2 as result from my_table where create_date> :PARAM_3
// 指定全局的SQL方言,默认MySQL,特定数据库时自动识别
GlobalSettings.DEFAULT_SQL_DIALECT= SQLDialect.MySQL;
System.out.println("开发人员友好的SQL(默认) = "+expr1.getSQL());
// 输出:开发人员友好的SQL(默认) = select 8 + 9 as result from my_table where create_date> str_to_date('2022-12-05 00:00:00','%Y-%m-%d %H:%i:%s')
System.out.println("开发人员友好的SQL(Oracle) = "+expr1.getSQL(SQLDialect.PLSQL));
// 输出:开发人员友好的SQL(Oracle) = select 8 + 9 as result from my_table where create_date> to_date('2022-12-05 00:00:00','yyyy-mm-dd hh24:mi:ss')
// 执行,此处请关注控制台输出日志
Expr exprForQuery=new Expr("select * from sys_dict where create_time>?",date);
RcdSet rs=DBInstance.DEFAULT.dao().query(exprForQuery);
for (Rcd r : rs) {
System.out.println(r.toJSONObject());
}
}
开发人员可以从表达式(Expr)获得比传统字符串拼接更加灵活,且绑定变量友好的SQL处理方式。也可以高效轻松地通过表达式避免数据库的SQL硬解析,从而获得更佳性能。
同时,开发人员可以轻松地获得绑定变量已代入的SQL语句,这些语句只要复制就可以粘贴到数据库客户端工具执行,极大地方便了SQL语句的调试与问题排查。
表达式拼装
Expr 可以通过 append 方法实现两个表达式的拼接,示例代码:
/**
* 3、表达式的拼装
* */
public static void demo3() {
// 示例-1
Expr expr1=new Expr("age>?",28);
Expr expr2=new Expr("and height>?",182);
// 通过 append 方法将 expr2 拼接到 expr1
expr1.append(expr2);
System.out.println(expr1.getSQL());
// 输出:age> 28 and height> 182
// 示例-2
Expr expr3=new Expr("age>?",28);
expr3.append("and height>?",182);
System.out.println(expr1.getSQL());
// 输出:age> 28 and height> 182
}
总结
Foxnic-SQL 的 Expr 类负责SQL语句、子语句、语句片段中的绑定变量的解析。其目的是时最终执行的SQL语句对JDBC友好、对开发人员友好。Expr 是 Foxnic-SQL 这个语句体系的基石,后续其它的语句对象都是由 Expr 继承或组合而来。
相关项目
https://gitee.com/LeeFJ/foxnic
https://gitee.com/LeeFJ/foxnic-web
https://gitee.com/lank/eam
https://gitee.com/LeeFJ/foxnic-samples