在使用Mybatis过程中,你可以体会到它的强大与灵活之处,由衷的为Mybatis之父点上999个赞!在使用过程中经常会遇到这样一种情况,我查询数据的时候,表名称是动态的从程序中传入的,比如我们通过mybatis的xml文件写sql查询时都是下面的样子:
1、正常的查询

1
2
3
<select id="activityEnrollModelTableName" parameterType="java.util.HashMap" resultType="java.util.HashMap">
SELECT * FROM user WHERE userid = #
</select>

上面的查询语句用mybatis执行时,其实是自动的按照JDBC的预编译语句方式执行的,等同于下面一段JDBC代码的执行过程

1
2
3
4
5
6
7
8
9
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManage.getConnection("jdbc:mysql://localhost:3306/dbname","root","112233");
PreparedStatement preState = conn.prepareStatement("SELECT * FROM user WHERE userid = ?");
preState.setString(1,"96");
ResultSet result = preState.executeQuery();
while(result.next()){
result.getString(columnname);
..........
}

到这里我们不禁疑惑,难道mybatis默认都是按照预编译语句的方式执行sql的吗?其实就是这样。通过查看mybatis官网文档可以看到有这么一个参数,statementType=[STATEMENT | PREPARED | CALLABLE ];有三个可选值,mybatis默认值是PREPARED;
这个参数是什么作用呢:

  1. 设定mybatis执行sql的模式
  2. STATEMENT设定为非预编译语句模式
  3. PREPARED设定为预编译语句模式–mybatis默认
  4. CALLABLE设定为兼容模式,或者自适应模式,比如设置该值后,mybatis处理sql时会自动的处理根据#、$去判断处理,后面说一下#和$的区别。

综上所述,mybatis默认按照预编译语句方式执行sql语句

2、动态传入表名

其实也经常会遇到动态的传入tableName的情况,也就是说上面的sql语句中的”user”是动态传入的,动态传入表名是mybatis中的一种特殊情况,

1
2
3
<select id="activityEnrollModelTableName" parameterType="java.util.HashMap" resultType="java.util.HashMap">
SELECT * FROM # WHERE userid = # //错误的写法
</select>

针对上面的语句,如果让mybatis仍然按照预编译语句方式执行时,等同于如下面的JDBC代码:

1
2
3
4
5
6
7
8
9
10
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManage.getConnection("jdbc:mysql://localhost:3306/dbname","root","112233");
PreparedStatement preState = conn.prepareStatement("SELECT * FROM ? WHERE userid = ?");
preState.setString(1,"USER");
preState.setString(2,"96");
ResultSet result = preState.executeQuery();
while(result.next()){
result.getString(columnname);
..........
}

我们把该段JDBC代码通过java代码执行后,发现会报异常:

1
java.sql.SQLException: ORA-00903: 表名无效

所以可以说明预编译语句不能用于列名(查询的列名也不能用预编译语句)、表名;只能作用与where条件参数属性!既然JDBC就不能将预编译语句方式作用与表名上面,那么mybatis就同样也行不通(因为mybatis默认是预编译语句模式)。不过mybatis也早已考虑到了这种情况,所以为我们做了处理:

  1. select标签语句中添加statementType=”STATEMENT”的属性配置
  2. 标签内的sql语句中将所有的${}更换成为#{},即将$还成#;
    1
    2
    3
    <select id="activityEnrollModelTableName" statementType="STATEMENT" parameterType="java.util.HashMap" resultType="java.util.HashMap">
    SELECT * FROM $ WHERE userid = $ //正确的写法
    </select>

上面的语句标签中通过添加statementType=”STATEMENT”配置后,mybatis就不再使用预编译语句方式执行sql语句了,也就是通过直接执行sql语句操作;那么既然添加了statementType=”STATEMENT”非预编译配置后,为什么还需要把#换成$呢?其实是这样:

    1. “#” 是预编译语句模式下面的默认匹配符,也就是说mybatis遇到#{}时,将#替换成占位符?;被解析为一个JDBC预编译语句,然后再将#本身的值set进来。
    2. “$” 是非预编译语句下面的匹配符,非预编译语句说白了就是你传入什么sql语句,就执行什么sql语句,mybatis不做任何处理操作,但是这里mybatis会将${}对应的值,当做一个字符串处理,也就是说你程序接口方法中传递过来参数值是什么,对应的sql填充就是什么!

Mybatis动态传入tableName--非预编译(STATEMENT)的更多相关文章

  1. mybatis中预编译sql与非预编译sql

    预编译sql有缓存作用,非预编译没得 mybaits中带有#传参的有预编译左右,$没得 多用#传参 预编译语句的优势在于归纳为:一次编译.多次运行,省去了解析优化等过程:此外预编译语句能防止sql注入 ...

  2. [转]MyBatis动态传入表名、字段名参数的解决办法

    一直在使用Mybatis这个ORM框架,都是使用mybatis里的一些常用功能.今天在项目开发中有个业务是需要限制各个用户对某些表里的字段查询以及某些字段是否显示,如某张表的某些字段不让用户查询到.这 ...

  3. MyBatis动态传入表名

    mybatis里#{}与${}的用法: 在动态sql解析过程,#{}与${}的效果是不一样的: #{ } 解析为一个 JDBC 预编译语句(prepared statement)的参数标记符. 如以下 ...

  4. MyBatis动态传入表名,字段名参数的解决办法---statementType用法

    statementType="STATEMENT" 要实现动态传入表名.列名,需要做如下修改 添加属性statementType="STATEMENT" 同时s ...

  5. MyBatis动态传入表名,字段名参数的解决办法

    原文:http://blog.csdn.net/xichenguan/article/details/50393748 要实现动态传入表名.列名,需要做如下修改 添加属性statementType=& ...

  6. mybatis动态传入表名、列名

    原文:http://luoyu-ds.iteye.com/blog/1517607 要实现动态传入表名.列名,需要做如下修改 添加属性statementType=”STATEMENT” (可省略) 同 ...

  7. oracle学习笔记(七) 预编译Statement介绍与使用

    预编译Statement优点 执行效率高 由于预编译语句使用占位符 "?",在执行SQL之前语句会被先发送到Oracle服务器进行语法检查和编译等工作,并将SQL语句加入到Orac ...

  8. JDBC预编译statement(preparedstatement)和statement的比较、execute与executeUpdate的区别

    和 Statement一样,PreparedStatement也是用来执行sql语句的与创建Statement不同的是,需要根据sql语句创建PreparedStatement除此之外,还能够通过设置 ...

  9. MyBatis,动态传入表名,字段名的解决办法

    转载:http://luoyu-ds.iteye.com/blog/1517607 今天做项目,遇到的问题就是需求修改数据表的记录,而且字段名都不是固定的,也就是说是需要通过参数传入的, 本来这也不是 ...

随机推荐

  1. ES5新增方法--查找方法--forEach(),filter(),some()区别

    1.forEach方法 迭代(遍历)数组 var arr = [1, 2, 3]; var sum = 0; arr.forEach(function (value, index, array) { ...

  2. 踩坑系列《五》 Incorrect datetime value: 时间添加失败原因

    在进行单元测试中通过 new Date() 方式添加时间时,报了 Data truncation: Incorrect datetime value:这样的错误(我数据库表的时间类型是 datetim ...

  3. Idea生成JavaDoc文档

    什么是JavaDoc javadoc是Sun公司提供的一个技术 它从程序源代码中抽取类.方法.成员等注释形成一个和源代码配套的API帮助文档 实现方式 命令行方式 javadoc -encoding ...

  4. Linux Bash命令杂记(tr col join paste expand)

    Linux Bash命令杂记(tr col join paste expand) tr命令 tr命令可以将输入的数据中的某些字符做替换或者是作删除 tr [-ds] STR d: 删除输入数据的中的S ...

  5. 解决VM 与 Device/Credential Guard 不兼容

    通过命令关闭Hyper-V(控制面板关闭Hyper-V起不到决定性作用,要彻底关闭Hyper-V) 以管理员身份运行Windows Powershell (管理员)(Windows键+X) 运行下面命 ...

  6. 题解 UVA1500 Alice and Bob

    题目传送门 题目大意 给出 \(n\) 堆石子,每次可以做以下两种操作之一: 将某两堆石子进行合并 将某一堆石子抽走一个石子 问谁必胜. 思路 就nm很妙好么? 首先,我们需要考虑每堆石子大小都 \( ...

  7. bzoj2037 Sue的小球(区间dp,考虑到对未来的贡献)

    ​​​​​​​​​​​​​​大致意思就是现在你要不断的奔跑到不同的地点去接球,每一秒可以移动一个单位长度,而你接到一个球的动作是瞬间的,收益是y[i]-t*v[i] 然后呢,要求分数最高. 起初看这个 ...

  8. 双系统升win11(grub启动问题修复与讲解)?!?

    起 最近win11不是出来了吗.(着急修复的可以直接跳到最后一步) 于是我就突发奇想给我半年没进去的windows升个级........ 于是我找到了我win11的升级包(从我一个同学哪儿) 工具都集 ...

  9. 听说,99% 的 Go 程序员都被 defer 坑过

    原文链接: 听说,99% 的 Go 程序员都被 defer 坑过 先声明:我被坑过. 之前写 Go 专栏时,写过一篇文章:Go 专栏|错误处理:defer,panic 和 recover.有小伙伴留言 ...

  10. MC-BE基岩版服务器搭建与日常维护

    有部分内容被csdn和谐,强烈建议移步我的个人博客以获得更好的排版和阅读体验: xzajyjs.cn. 目录 环境搭建 开始部署 日常维护 服务器的白名单机制 定时备份 服务器升级 服务器模组安装 搭 ...