MyBatis 执行动态 SQL语句详解_java

大家基本上都知道如何使用 MyBatis 执行任意 SQL,使用方法很简单,例如在一个 XXMapper.xml 中:

<select id="executeSql" resultType="map">
${_parameter}
</select>

你可以如下调用:

sqlSession.selectList("executeSql", "select * from sysuser where enabled = 1");

或者你可以在 XXMapper.java 接口中定义如下方法:

List<Map> executeSql(String sql);

然后使用接口调用方法:

xxMapper.executeSql("select * from sysuser where enabled = 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},'%')

这种情况下,该怎么用 MyBatis 实现呢?

首先 XML 中修改如下:

<select id="executeSql" resultType="map">
${sql}
</select>

接口中的方法修改为:

List<Map> executeSql(Map map);

然后调用方法:

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);

有了这个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;
}

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>

注意,这里的<#if>是Freemarker的元素。在不考虑SQL注入的情况下,上面的SQL还可以写成:

select * from sysuser
where 1 = 1
<#if enabled??>
enabled = #{enabled}
</#if>
<#if userName?? && userName != ''>
and userName like '%${userName}%'
</#if>

区别就是'%${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", "select * from sysuser "
+ " where enabled = #{enabled} "
+ " and userName like concat('%',#{userName},'%')");
//执行方法
List<Map> list = xxMapper.executeSql(map);

注:processSqlByFreemarker方法就是根据map中的数据来处理sql字符串,实现方式可以自己搜索。

到这里,一个不是很复杂的动态SQL功能就实现了。

不知道有没有更贪心的人,你会不会想,上面返回值都是List<Map>类型,能不能返回一个我指定的实体类呢?

例如在map中:

map.put("class", "tk.mybatis.model.SysUser");

能不能通过这种方式让返回值变成SysUser类型呢?由于这篇文章耗时已经太长,这里就提供一个方案,不深入。

你可以使用拦截器实现,获取 MappedStatement 后,复制一份,然后修改 resultMaps中resultMap的type属性为你指定的class类型就能实现,说起来容易,实际操作起来能有 PageHelper 分页插件 1/10 左右的工作量。

因为这篇是应媳妇要求所写,所以假如媳妇有最后的这个需求,我就协助媳妇实现这个插件,然后再共享出来。

注:如果是动态的update,insert,delete 语句,可以将上面的<select>改为update(不需要使用<delete>和<insert>),返回值用int,比 select 的情况容易很多。

以上所述是小编给大家介绍的MyBatis 执行动态 SQL语句详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索mybatis
, 动态sql
执行SQL
mybatis 动态sql语句、mybatis动态sql详解、mybatis执行多条语句、mybatis执行sql语句、mybatis执行建表语句,以便于您获取更多的相关知识。

时间: 2024-12-02 01:56:31

MyBatis 执行动态 SQL语句详解_java的相关文章

MySQL存储过程中实现执行动态SQL语句的方法_Mysql

本文实例讲述了MySQL存储过程中实现执行动态SQL语句的方法.分享给大家供大家参考.具体实现方法如下: mysql> mysql> delimiter $$ mysql> mysql> CREATE PROCEDURE set_col_value -> (in_table VARCHAR(128), -> in_column VARCHAR(128), -> in_new_value VARCHAR(1000), -> in_where VARCHAR(4

在存储过程中执行动态sql语句,能否提高性能

问题描述 原本在后台写的sql语句很复杂,属于多表连接操作,现在把它放在了存储过程里用动态sqlexec执行,能否提高性能呢 解决方案 解决方案二:1.可以减轻程序负担,把这些工作都交给DBMS2.程序维护起来更加简单3.仅是个人观点解决方案三:存储过程执行动态sql语句时结尾exec(@sql)和execsp_executesql@sql有何区别解决方案四:差不多的,要提高用存储过程好了解决方案五:但是参数是要动态的,必须用动态SQL

使用Oracle的DBMS_SQL包执行动态SQL语句

引用自:http://blog.csdn.net/ggjjzhzz/archive/2005/10/17/507880.aspx 在某些场合下,存储过程或触发器里的SQL语句需要动态生成.Oracle的DBMS_SQL包可以用来执行动态SQL语句.本文通过一个简单的例子来展示如何利用DBMS_SQL包执行动态SQL语句:   DECLARE        v_cursor NUMBER;        v_stat NUMBER;        v_row NUMBER;        v_id

MyBatis的foreach语句详解_java

foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合.foreach元素的属性主要有 item,index,collection,open,separator,close.item表示集合中每一个元素进行迭代时的别名,index指 定一个名字,用于表示在迭代过程中,每次迭代到的位置,open表示该语句以什么开始,separator表示在每次进行迭代之间以什么符号作为分隔 符,close表示以什么结束,在使用foreach的时候最关键的也是最容易出错的就是collectio

Java下拼接执行动态SQL语句(转)

       在实际业务中经常需要拼接动态SQL来完成复杂数据计算,网上各类技术论坛都有讨论,比如下面这些问题:         http://bbs.csdn.net/topics/390876591         http://bbs.csdn.net/topics/390981627         https://www.linkedin.com/groups/SQL-Query-Help-needed-137774.S.5948812806903119877?trk=groups_i

MySQL 存储过程中执行动态SQL语句的方法_Mysql

drop PROCEDURE if exists my_procedure; create PROCEDURE my_procedure() BEGIN declare my_sqll varchar(500); set my_sqll='select * from aa_list'; set @ms=my_sqll; PREPARE s1 from @ms; EXECUTE s1; deallocate prepare s1; end; 以上是小编为您精心准备的的内容,在的博客.问答.公众号.

SQL SERVER 中构建执行动态SQL语句的方法

1 :普通SQL语句可以用exec执行 Select * from tableName exec('select * from tableName') exec sp_executesql N'select * from tableName' -- 请注意字符串前一定要加N 2:字段名,表名,数据库名之类作为变量时,必须用动态SQL declare @fname varchar(20) set @fname = 'FiledName' --Select @fname from tableName

oracle基础sql语句详解

二.SQL Structur query language 结构化查询语言,是操作关系型数据库中的对象. DDL(Data definition language 数据定义语言),用于建表或删表操作,以及对表约束进行修改 create table , alter table , drop table 对表结构的增删操作. DML(Data manipulation language 数据操作语言),向表中插入纪录,修改纪录 insert , update , delete , merge tra

java跟踪执行的sql语句示例分享_java

代码: 复制代码 代码如下: package com.lwj.test.proxy; import java.lang.reflect.InvocationHandler;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.sql.Connection;import java.sql.SQLExce