mybatis中的字符串拼接问题

 更新时间:2023年02月07日 09:11:33   作者:藤原·拓海  
这篇文章主要介绍了mybatis中的字符串拼接问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

mybatis字符串拼接

MyBatis中拼接字符串有两种方式。

使用CONCAT 函数

SELECT * FROM user WHERE name LIKE CONCAT(CONCAT(‘%', #{name}), ‘%')

使用${ } 代替 #{ }

因为${ }直接传入SQL,而#{ }传入的是字符串带有引号

SELECT * FROM user WHERE name LIKE ‘%${name}%'

原因:

#{}能够有效防止SQL注入,但是也有它的缺点,它会把传入的数据自动加上一个双引号,所以如果要的是数字的话,就会比较尴尬。

而${}可以直接解析出原本的数据,所以需要数值比较的话,还是要加${}。

mybatis 拼接动态表名、字段名

在项目中遇到个需求是要动态的根据前台传入的字段名称和升降序条件在mybatis里动态拼接sql语句进行查询。现在对解决方法进行下总结,希望对遇到同样问题的伙伴有些帮助。

动态SQL是mybatis的强大特性之一,mybatis在对sql语句进行预编译之前,会对sql进行动态解析,解析为一个BoundSql对象,也是在此处对动态sql进行处理。

这里我们详细说下动态表名和字段名。下面让我们先来熟悉下mybatis里#{}与${}的用法:

在动态sql解析过程,#{}与${}的效果是不一样的:

#{ } 解析为一个 JDBC 预编译语句(prepared statement)的参数标记符。

如以下sql语句

select * from user where name = #{name};

会被解析为:

select * from user where name = ?;

可以看到#{}被解析为一个参数占位符?。

${ } 仅仅为一个纯碎的 string 替换,在动态 SQL 解析阶段将会进行变量替换

如以下sql语句:

select * from user where name = ${name};

当我们传递参数“sprite”时,sql会解析为:

select * from user where name = "sprite";

可以看到预编译之前的sql语句已经不包含变量name了。

综上所得, ${ } 的变量的替换阶段是在动态 SQL 解析阶段,而 #{ }的变量的替换是在 DBMS 中。

#{}与${}的区别可以简单总结如下:

  • #{}将传入的参数当成一个字符串,会给传入的参数加一个双引号
  • ${}将传入的参数直接显示生成在sql中,不会添加引号
  • #{}能够很大程度上防止sql注入,${}无法防止sql注入

${}在预编译之前已经被变量替换了,这会存在sql注入的风险。如下sql

select * from ${tableName} where name = ${name}

如果传入的参数tableName为user; delete user; --,那么sql动态解析之后,预编译之前的sql将变为:

select * from user; delete user; -- where name = ?;
--之后的语句将作为注释不起作用,顿时我和我的小伙伴惊呆了!!!看到没,本来的查询语句,竟然偷偷的包含了一个删除表数据的sql,是删除,删除,删除!!!重要的事情说三遍,可想而知,这个风险是有多大。
  • ${}一般用于传输数据库的表名、字段名等
  • 能用#{}的地方尽量别用${}

进入正题,通过上面的分析,相信大家可能已经对如何动态调用表名和字段名有些思路了。示例如下:

  <select id="getUser" resultType="java.util.Map" parameterType="java.lang.String" statementType="STATEMENT">
    select 
        ${columns}
    from ${tableName}
        where COMPANY_REMARK = ${company}
  </select>

要实现动态调用表名和字段名,就不能使用预编译了,需添加statementType="STATEMENT"" 。

statementType:STATEMENT(非预编译),PREPARED(预编译)或CALLABLE中的任意一个,这就告诉 MyBatis 分别使用Statement,PreparedStatement或者CallableStatement。默认:PREPARED。这里显然不能使用预编译,要改成非预编译。

其次,sql里的变量取值是${xxx},不是#{xxx}。

因为${}是将传入的参数直接显示生成sql,如${xxx}传入的参数为字符串数据,需在参数传入前加上引号,如:

String name = "sprite";
name = "'" + name + "'";

这样,sql就变成:

select * from user where name = 'sprite';

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java实现简易的分词器功能

    Java实现简易的分词器功能

    搜索功能是具备数据库功能的系统的一大重要特性和功能,生活中常见的搜索功能基本上都具备了分词搜索功能.然而ES功能固然强大,但对于学生或小项目而言整合起来太费人力物力,若是写个分词器就会使项目锦上添花,使其不仅仅是只能单关键词搜索的系统,需要的朋友可以参考下
    2021-06-06
  • Servlet映射路径匹配解析详解

    Servlet映射路径匹配解析详解

    servlet是javaweb用来处理请求和响应的重要对象,本文将从源码的角度分析tomcat内部是如何根据请求路径匹配得到处理请求的servlet的,感兴趣的可以了解一下
    2022-08-08
  • Java使用阻塞队列控制线程通信的方法实例详解

    Java使用阻塞队列控制线程通信的方法实例详解

    这篇文章主要介绍了Java使用阻塞队列控制线程通信的方法,结合实例形式详细分析了java使用阻塞队列控制线程通信的相关原理、方法及操作注意事项,需要的朋友可以参考下
    2019-09-09
  • 快速了解JAVA中的Random()函数

    快速了解JAVA中的Random()函数

    这篇文章主要介绍了JAVA中的Random()函数的使用方法,文中代码非常详细,供大家参考和学习,感兴趣的朋友可以了解下
    2020-06-06
  • Java数组的定义与使用

    Java数组的定义与使用

    数组是有序的元素序列,若将有限个类型相同的变量的集合命名,那么这个名称为数组名。本文通过代码示例详细介绍了Java数组的定义和使用,对学习或工作有一定的帮助,需要的小伙伴欢迎阅读
    2023-04-04
  • Java中ThreadLocal线程变量的实现原理

    Java中ThreadLocal线程变量的实现原理

    本文主要介绍了Java中ThreadLocal线程变量的实现原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06
  • Spring Boot启动流程分析

    Spring Boot启动流程分析

    本文给大家介绍spring boot是怎样启动和启动做了哪些事情。具体内容详情大家通过本文详细学习吧
    2017-09-09
  • OGNL表达式基本语法与用法详解

    OGNL表达式基本语法与用法详解

    这篇文章主要介绍了OGNL表达式基本语法与用法详解,具有一定参考价值。需要的朋友可以了解下。
    2017-09-09
  • idea全局设置Maven配置的实现步骤

    idea全局设置Maven配置的实现步骤

    本文主要介绍了idea全局设置Maven配置,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • 详解Java中List接口底层实现原理

    详解Java中List接口底层实现原理

    Java是一种广泛应用的编程语言,被广泛应用于各种平台和应用领域,List接口是Java中最重要的数据结构之一,它为我们提供了一种灵活、高效、可扩展的数据结构,本篇文章将首先介绍Java中List接口的基本特性和使用方法,然后深入研究List接口的底层实现原理
    2023-11-11

最新评论