使用MyBatis动态生成sql
Posted huanghanqian
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用MyBatis动态生成sql相关的知识,希望对你有一定的参考价值。
问题举例:
有一个带占位符的模板sql,语法跟mybatis的XML是类似的,如
select period, sum(amount) as sum from abc where type = '${type}'
<if test='period != null'>
and period = '${period}'
</if>
<if test='debtType != null'>
and debt_type = '${debtType}'
</if>
和 动态的参数,如:
{"type": "fruit", "period": "2021-01"}
参数是动态的,因为有可能是实时从页面上传过来的。
希望生成的sql是:
select period, sum(amount) as sum from abc where type = 'fruit' and period = '2021-01';
那么,如果想通过这样的模板sql,加上动态参数,来动态生成sql,应该怎么做呢?
(这里感谢聪明帅气的师兄:哲哥(elon_wen) 的帮助,查遍stackoverflow都没有方案,但是他却找到了方案!)
MyBatis提供了这样的方案:
public static void main(String[] args) throws Exception {
String script = "<script>select * from table where 1 = 1<if test='id != null'>and id = ${id} </if></script>";
System.out.println(buildSql(script));
// 打印出来的结果是:select * from table where 1 = 1 and id = 1
}
private static String buildSql(String script) {
LanguageDriver languageDriver = new XMLLanguageDriver();
Configuration configuration = new Configuration();
SqlSource sqlSource = languageDriver.createSqlSource(configuration, script, Object.class);
Map<String, String> parameters = new HashMap<>();
parameters.put("id", "1");
BoundSql boundSql = sqlSource.getBoundSql(parameters);
return boundSql.getSql();
}
需要注意的是,这里的模板sql里的占位符,需要使用 ${id} ,而不是 #{id},不然打印出来的是问号(因为变成了PreparedStatement,具体见https://stackoverflow.com/questions/33197085/mybatis-3-get-sql-string-from-mapper/33197157#33197157)。同时,这种方式也不能防止sql注入。
以上是关于使用MyBatis动态生成sql的主要内容,如果未能解决你的问题,请参考以下文章
Mybatis -- 动态Sql概述动态Sql之<if>(包含<where>)动态Sql之<foreach>sql片段抽取
[mybatis]动态sql_sql_抽取可重用的sql片段