大家基本上都知道如何使用 mybatis 执行任意 sql,使用方法很简单,例如在一个 xxmapper.xml 中:
| 
								1
 
								2
 
								3
						 | <select id="executesql"resulttype="map">${_parameter}</select> | 
你可以如下调用:
| 
								1
						 | sqlsession.selectlist("executesql", "select * from sysuser where enabled = 1"); | 
或者你可以在 xxmapper.java 接口中定义如下方法:
| 
								1
						 | list<map> executesql(string sql); | 
然后使用接口调用方法:
| 
								1
						 | xxmapper.executesql("select * from sysuser where enabled = 1"); | 
上面这些内容可能都会,下面在此基础上再复杂一点。
	假如像上面sql中的enabled = 1我想使用参数方式传值,也就是写成enabled = #{enabled},如果你没有遇到过类似这种需求,可能不明白为什么要这么写,举个例子,要实现一种动态查询,可以在前台通过配置 sql,提供一些查询条件就能实现一个查询的功能(为了安全,这些配置肯定是开发或者实施做的,不可能让用户直接操作数据库)。
	针对这个功能,使用 mybatis 实现起来相当容易。配置 sql 肯定要执行,用上面讲的这种方式肯定可以执行 sql,如何提供参数呢?参数就是enabled = #{enabled}中的#{enabled}部分。如果再多一些条件,一个配置好的 sql 如下:
| 
								1
 
								2
 
								3
						 | select * from sysuser where enabled = #{enabled} and username like concat('%',#{username},'%') | 
这种情况下,该怎么用 mybatis 实现呢?
首先 xml 中修改如下:
| 
								1
 
								2
 
								3
						 | <select id="executesql"resulttype="map">${sql}</select> | 
接口中的方法修改为:
| 
								1
						 | list<map> executesql(map map); | 
然后调用方法:
| 
								1
 
								2
 
								3
 
								4
 
								5
 
								6
 
								7
 
								8
 
								9
 
								10
 
								11
 
								12
 
								13
						 | map map = newhashmap();//这里的 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中的代码:
| 
								1
 
								2
 
								3
 
								4
 
								5
 
								6
 
								7
 
								8
 
								9
 
								10
 
								11
 
								12
 
								13
 
								14
 
								15
						 | @overridepublicboundsql getboundsql(object parameterobject) {dynamiccontext context = newdynamiccontext(configuration, parameterobject);rootsqlnode.apply(context);sqlsourcebuilder sqlsourceparser = newsqlsourcebuilder(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());}returnboundsql;} | 
	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为基础:
| 
								1
 
								2
 
								3
 
								4
 
								5
 
								6
 
								7
 
								8
						 | select * from sysuser where 1= 1<#ifenabled??>enabled = #{enabled} </#if><#ifusername?? && username != ''>and username like concat('%',#{username},'%')</#if> | 
	注意,这里的<#if>是freemarker的元素。在不考虑sql注入的情况下,上面的sql还可以写成:
| 
								1
 
								2
 
								3
 
								4
 
								5
 
								6
 
								7
 
								8
						 | select * from sysuser where 1= 1<#ifenabled??>enabled = #{enabled} </#if><#ifusername?? && username != ''>and username like '%${username}%'</#if> | 
	区别就是'%${username}%',因为 freemarker 也会处理${username},也会用实际的值来替换这里的参数。
在前面调用的代码中,这里修改如下:
| 
								1
 
								2
 
								3
 
								4
 
								5
 
								6
 
								7
 
								8
 
								9
 
								10
 
								11
 
								12
						 | //#{enabled}map.put("enabled", 1);//#{username}map.put("username", "admin");//这里的 sql 对应 xml 中的 ${sql}string sql = "上面两个复杂sql中的一个";//使用freemarker处理sqlsql = processsqlbyfreemarker(sql, map);//将处理后的sql放到map中map.put("sql", sql);//执行方法list<map> list = xxmapper.executesql(map); | 
	注:processsqlbyfreemarker方法就是根据map中的数据来处理sql字符串,实现方式可以自己搜索。
到这里,一个不是很复杂的动态sql功能就实现了。
	不知道有没有更贪心的人,你会不会想,上面返回值都是list<map>类型,能不能返回一个我指定的实体类呢?
例如在map中:
| 
								1
						 | 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的情况容易很多。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对快网idc的支持。如果你想了解更多相关内容请查看下面相关链接
原文链接:https://blog.csdn.net/isea533/article/details/52368341
相关文章
- 个人服务器网站搭建:如何选择合适的服务器提供商? 2025-06-10
- ASP.NET自助建站系统中如何实现多语言支持? 2025-06-10
- 64M VPS建站:如何选择最适合的网站建设平台? 2025-06-10
- ASP.NET本地开发时常见的配置错误及解决方法? 2025-06-10
- ASP.NET自助建站系统的数据库备份与恢复操作指南 2025-06-10
- 2025-07-10 怎样使用阿里云的安全工具进行服务器漏洞扫描和修复?
- 2025-07-10 怎样使用命令行工具优化Linux云服务器的Ping性能?
- 2025-07-10 怎样使用Xshell连接华为云服务器,实现高效远程管理?
- 2025-07-10 怎样利用云服务器D盘搭建稳定、高效的网站托管环境?
- 2025-07-10 怎样使用阿里云的安全组功能来增强服务器防火墙的安全性?
快网idc优惠网
QQ交流群
- 
            2025-05-24 98
- 
            2025-05-29 36
- 
            2025-05-29 37
- 
            2025-05-29 94
- 
            2025-05-29 20
 
        
 
    		 
            	 
															 
         
         
        
 
                        