mybatis动态调用表名和字段名

  一直在使用Mybatis这个ORM框架,都是使用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 + "'";

mybatis动态调用表名和字段名,还可以应用于日志的收集上,如数据库的日志表,每隔一个月动态建一个日志表,表名前缀相同(如log_201610,log_201611等),这样实现日志的分月分表存储,方便日志的分析。

希望对大家有帮助!如有疑问可以在底下留言。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java帮帮-微信公众号-技术文章全总结

Mybatis框架复习大纲【面试+提高】

Mybatis框架复习大纲【面试+提高】 1.MyBatis面试题汇总 1.1 JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的? ① 数据库链...

54270
来自专栏同步博客

单例模式

  一种是饿汉式单例,饿汉式单例在单例类被加载时候,就实例化一个对象交给自己的引用;

15230
来自专栏PingCAP的专栏

TiDB 源码阅读系列文章(十)Chunk 和执行框架简介

Chunk 本质上是 Column 的集合,它负责连续的在内存中存储同一列的数据,接下来我们看看 Column 的实现。

5.7K1450
来自专栏Java面试通关手册

深入理解单例模式

Java面试通关手册(Java学习指南,欢迎Star,会一直完善下去,欢迎建议和指导):https://github.com/Snailclimb/Java_G...

19860
来自专栏HappenLee的技术杂谈

存储与索引------《Designing Data-Intensive Applications》读书笔记3

键值对数据库是数据库形式之中最简单的一种模式,我们可以把它简化的实现为下面两个函数:

14420
来自专栏Java进阶之路

java单例模式之我看

19600
来自专栏orientlu

FreeRTOS 任务调度 任务创建

FreeRTOS 的任务调度在 Source/include/task.c 中实现,包含了任务的创建、切换、挂起、延时和删除等所有功能。涉及到的链表组织见文章 ...

32840
来自专栏跟着阿笨一起玩NET

C#设计模式学习笔记-单例模式

  最近在学设计模式,学到创建型模式的时候,碰到单例模式(或叫单件模式),现在整理一下笔记。

9820
来自专栏JavaEE

mybatis-plus的使用 ------ 入门

mybatis在持久层框架中还是比较火的,一般项目都是基于ssm。虽然mybatis可以直接在xml中通过SQL语句操作数据库,很是灵活。但正其操作都要通过SQ...

4.2K40
来自专栏GreenLeaves

存储过程详解

存储过程简介 什么是存储过程:存储过程可以说是一个记录集吧,它是由一些T-SQL语句组成的代码块,这些T-SQL语句代码像一个方法一样实现一些功能(对单表或多表...

226100

扫码关注云+社区

领取腾讯云代金券