• Mybatis动态传入tableName--非预编译(STATEMENT)


    在使用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填充就是什么!
  • 相关阅读:
    再谈每周工作不要超过 40 小时
    前苹果雇员潜入总部 只为完成自己的项目
    C语言解析pcap文件得到HTTP信息实例(原创,附源码)
    Android 2.1 源码结构分析
    linux 获取当前日期与时间
    谷歌史上十大优秀产品榜:Android傲娇上位
    在eclipse中查看android SDK的源代码
    网络开发必备的HTTP协议知识
    Linux TCP/IP协议栈源码阅读笔记
    浅析UPnP协议
  • 原文地址:https://www.cnblogs.com/mxj961116/p/11907187.html
Copyright © 2020-2023  润新知