MyBatis 执行动态 SQL
2017-02-19 21:17
405 查看
应老婆要求写的这篇博客。
大家基本上都知道如何使用 MyBatis 执行任意 SQL,使用方法很简单,例如在一个 XXMapper.xml 中:
2
3
1
2
3
你可以如下调用:
1
或者你可以在 XXMapper.Java 接口中定义如下方法:
1
然后使用接口调用方法:
1
上面这些内容可能都会,下面在此基础上再复杂一点。
假如像上面SQL中的
针对这个功能,使用 MyBatis 实现起来相当容易。配置 SQL 肯定要执行,用上面讲的这种方式肯定可以执行 SQL,如何提供参数呢?参数就是
SQL 如下:
2
3
1
2
3
这种情况下,该怎么用 MyBatis 实现呢?
首先 XML 中修改如下:
2
3
1
2
3
接口中的方法修改为:
1
然后调用方法:
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
有了这个SQL之后,就可以将 enabled 和 userName 作为条件提供给用户。这两个条件显然是必填的。如果是可选的,那该怎么写?
也许有人想到了是不是可以用 MyBatis 中的动态 SQL,使用
再回答这个问题前,我们先看处理动态 SQL 的
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
MyBatis 处理动态 SQL 时,所有动态 SQL 的标签都会处理为 SqlNode (这里的
MyBatis 处理动态 SQL 的地方。
因此如果我们在
MyBatis 解析 XML 为 SqlNode 对象时,XML
MyBatis 解析后,因此当这些内容作为字符串中的一部分出现时,他们不会被特殊处理,他们只是SQL中的一部分,只是原样输出(由于数据库不认会报错)无法被处理,因此没法通过 MyBatis 自带的这种方式来写动态 SQL。
提示
在上面的代码中:
这一段代码是处理动态参数(
这个处理在动态 SQL 处理之后,
因此可以在 SQL 中使用这种类型的参数。
既然不能用 MyBatis 动态 SQL 方式,该怎么实现动态 SQL 呢?
这里提供一个简单的思路,在 SQL 中使用模板标记语言来实现动态SQL(例如freemarker),在 SQL 交给 MyBatis 执行之前,使用模板对 SQL 进行处理生成最终执行的 SQL(需要避免处理
MyBatis 执行。
举一个Freemarker模板的例子,仍然以上面的SQL为基础:
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
注意,这里的
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
区别就是
在前面调用的代码中,这里修改如下:
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
注:
到这里,一个不是很复杂的动态SQL功能就实现了。
不知道有没有更贪心的人,你会不会想,上面返回值都是
例如在map中:
1
能不能通过这种方式让返回值变成
你可以使用拦截器实现,获取
PageHelper 分页插件 1/10 左右的工作量。
因为这篇是应媳妇要求所写,所以假如媳妇有最后的这个需求,我就协助媳妇实现这个插件,然后再共享出来(这个插件已经实现,参考 MyBatis 返回动态结果类型插件 )。
注:如果是动态的update,insert,delete 语句,可以将上面的
from: http://blog.csdn.net/isea533/article/details/52368341
大家基本上都知道如何使用 MyBatis 执行任意 SQL,使用方法很简单,例如在一个 XXMapper.xml 中:
<select id="executeSql" resultType="map"> ${_parameter} </select>1
2
3
1
2
3
你可以如下调用:
sqlSession.selectList("executeSql", "select * from sysuser where enabled = 1");1
1
或者你可以在 XXMapper.Java 接口中定义如下方法:
List<Map> executeSql(String sql);1
1
然后使用接口调用方法:
xxMapper.executeSql("select * from sysuser where enabled = 1");1
1
上面这些内容可能都会,下面在此基础上再复杂一点。
假如像上面SQL中的
enabled = 1我想使用参数方式传值,也就是写成
enabled = #{enabled},如果你没有遇到过类似这种需求,可能不明白为什么要这么写,举个例子,要实现一种动态查询,可以在前台通过配置 SQL,提供一些查询条件就能实现一个查询的功能(为了安全,这些配置肯定是开发或者实施做的,不可能让用户直接操作数据库)。
针对这个功能,使用 MyBatis 实现起来相当容易。配置 SQL 肯定要执行,用上面讲的这种方式肯定可以执行 SQL,如何提供参数呢?参数就是
enabled = #{enabled}中的
#{enabled}部分。如果再多一些条件,一个配置好的
SQL 如下:
select * from sysuser where enabled = #{enabled} and userName like concat('%',#{userName},'%')1
2
3
1
2
3
这种情况下,该怎么用 MyBatis 实现呢?
首先 XML 中修改如下:
<select id="executeSql" resultType="map"> ${sql} </select>1
2
3
1
2
3
接口中的方法修改为:
List<Map> executeSql(Map map);1
1
然后调用方法:
Map map = new HashMap(); //这里的 sql 对应 XML 中的 ${sql} map.put("sql", "select * from sysuser " + " where enabled = #{enabled} " + " and userName like concat('%',#{userName},'%')"); //#{enabled} map.put("enabled", 1); //#{userName} map.put("userName", "admin"); //接口方式调用 List<Map> list = xxMapper.executeSql(map); //sqlSession方式调用 sqlSession.selectList("executeSql", map);1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
有了这个SQL之后,就可以将 enabled 和 userName 作为条件提供给用户。这两个条件显然是必填的。如果是可选的,那该怎么写?
也许有人想到了是不是可以用 MyBatis 中的动态 SQL,使用
<if>标签等等?
再回答这个问题前,我们先看处理动态 SQL 的
DynamicSqlSource中的代码:
@Override public BoundSql getBoundSql(Object parameterObject) { DynamicContext context = new DynamicContext(configuration, parameterObject); rootSqlNode.apply(context); SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration); Class < ?>parameterType = parameterObject == null ? Object.class: parameterObject.getClass(); SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings()); BoundSql boundSql = sqlSource.getBoundSql(parameterObject); for (Map.Entry < String, Object > entry: context.getBindings().entrySet()) { boundSql.setAdditionalParameter(entry.getKey(), entry.getValue()); } return boundSql; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
MyBatis 处理动态 SQL 时,所有动态 SQL 的标签都会处理为 SqlNode (这里的
rootSqlNode)对象,包含
${}的也会处理为
TextSqlNode对象,在上面方法的前两行,就是
MyBatis 处理动态 SQL 的地方。
因此如果我们在
${sql}中的内容包含嵌套的
${}和
<if>,
<where>等标签时,他们在
MyBatis 解析 XML 为 SqlNode 对象时,XML
<select>元素包含的内容只有
${sql},只有
${sql}会被解析,在运行时这个参数字符串中可能包含的
${}和
<if>,
<where>等标签,但是这都发生在
MyBatis 解析后,因此当这些内容作为字符串中的一部分出现时,他们不会被特殊处理,他们只是SQL中的一部分,只是原样输出(由于数据库不认会报错)无法被处理,因此没法通过 MyBatis 自带的这种方式来写动态 SQL。
提示
在上面的代码中:
sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
这一段代码是处理动态参数(
#{})的
这个处理在动态 SQL 处理之后,
因此可以在 SQL 中使用这种类型的参数。
既然不能用 MyBatis 动态 SQL 方式,该怎么实现动态 SQL 呢?
这里提供一个简单的思路,在 SQL 中使用模板标记语言来实现动态SQL(例如freemarker),在 SQL 交给 MyBatis 执行之前,使用模板对 SQL 进行处理生成最终执行的 SQL(需要避免处理
#{}参数),将这个SQL交给
MyBatis 执行。
举一个Freemarker模板的例子,仍然以上面的SQL为基础:
select * from sysuser where 1 = 1 <#if enabled??> enabled = #{enabled} </#if> <#if userName?? && userName != ''> and userName like concat('%',#{userName},'%') </#if>1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
注意,这里的
<#if>是Freemarker的元素。在不考虑SQL注入的情况下,上面的SQL还可以写成:
select * from sysuser where 1 = 1 <#if enabled??> enabled = #{enabled} </#if> <#if userName?? && userName != ''> and userName like '%${userName}%' </#if>1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
区别就是
'%${userName}%',因为 Freemarker 也会处理
${userName},也会用实际的值来替换这里的参数。
在前面调用的代码中,这里修改如下:
//#{enabled} map.put("enabled", 1); //#{userName} map.put("userName", "admin"); //这里的 sql 对应 XML 中的 ${sql} String sql = "上面两个复杂SQL中的一个"; //使用Freemarker处理sql sql = processSqlByFreemarker(sql, map); //将处理后的sql放到map中 map.put("sql", sql); //执行方法 List<Map> list = xxMapper.executeSql(map);1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
注:
processSqlByFreemarker方法就是根据map中的数据来处理sql字符串,实现方式可以自己搜索。
到这里,一个不是很复杂的动态SQL功能就实现了。
不知道有没有更贪心的人,你会不会想,上面返回值都是
List<Map>类型,能不能返回一个我指定的实体类呢?
例如在map中:
map.put("class", "tk.mybatis.model.SysUser");1
1
能不能通过这种方式让返回值变成
SysUser类型呢?由于这篇文章耗时已经太长,这里就提供一个方案,不深入。
你可以使用拦截器实现,获取
MappedStatement后,复制一份,然后修改
resultMaps中
resultMap的
type属性为你指定的
class类型就能实现,说起来容易,实际操作起来能有
PageHelper 分页插件 1/10 左右的工作量。
因为这篇是应媳妇要求所写,所以假如媳妇有最后的这个需求,我就协助媳妇实现这个插件,然后再共享出来(这个插件已经实现,参考 MyBatis 返回动态结果类型插件 )。
注:如果是动态的update,insert,delete 语句,可以将上面的
<select>改为
<update>(不需要使用
<delete>和
<insert>),返回值用
int,比
select的情况容易很多。
from: http://blog.csdn.net/isea533/article/details/52368341
相关文章推荐
- MyBatis 执行动态 SQL语句详解
- mybatis 动态sql 根据条件执行相应的语句
- mybatis执行动态sql语句
- Mybatis动态SQL执行批量更新注意事项
- MyBatis 动态SQL的单参数不执行问题
- mybatis动态sql根据java枚举判断不执行,执行otherwise,解决办法
- mybatis执行动态sql语句
- MyBatis执行动态sql及存储过程
- MyBatis 执行动态 SQL
- 动态执行Sql语句与临时表的问题(对象名无效)
- MySql带参数的存储过程编写(动态执行SQL语句)
- PL/SQL块或者存储过程中不能执行DDL,可以使用动态SQL
- SQL Server - 执行动态SQL
- sql server 存储过程中执行带输出参数的动态 sql
- 使用Oracle的DBMS_SQL包执行动态SQL语句
- 动态执行SQL语句,“SELECT TOP N *”语句中“N”不能为变量的解决方案
- PLSQL中执行本地动态SQL
- 使用DBMS_SQL包动态执行sql
- SP中执行动态组串的sql
- 用存储过程动态生成sql语句并执行