MyBatis(四)映射文件 之 参数获取详解#{} 与 ${}

摘要:
select*from2016_salaryselect*from${year}_salarywherexxx;select*fromemporderby${f_name}${order}二、使用#{}与${}取值  1、#{}取值EmployeeMapper接口中的方法:publicvoidinsertEmp;EmployeeMapper.xml中的配置:insertintotbl_employeevalues运行结果:可以发现这时并没有运行成功,这条SQL语句与数据库的类型不匹配。再次修改mapper.xml,给${}加上单引号!  3、总结获取参数值有两种方式:#{}与${}#{}这种方式获取值,执行SQL时,是使用PreparedStatement,使用?--publicEmployeegetEmployeeById;--˃selectid,last_namelastName,email,genderfromtbl_employeewhereid=#{aaa}运行结果:可以看出,修改了SQL语句中的参数名字,也可以获取参数并赋值成功!
一、#{} 与${} 的取值

相同点:

#{}:可以获取map中的值或者pojo对象属性的值;
${}:可以获取map中的值或者pojo对象属性的值;

区别:

#{}:是以预编译的形式,将参数设置到sql语句中;PreparedStatement;防止sql注入;

${}:取出的值直接拼装在sql语句中;会有安全问题;

大多情况下,我们去参数的值都应该去使用#{};

什么情况下会使用 ${} 呢?

在原生 jdbc 不支持占位符的地方就可以使用${} 进行取值,比如分表(表名的拼接,按照年份分表拆分)、排序等。

select * from 2016_salary
select * from ${year}_salary where xxx;
select * from emp order by ${f_name} ${order}
二、使用#{} 与 ${} 取值

  1、#{} 取值

EmployeeMapper 接口中的方法:

public void insertEmp(Employee employee);

EmployeeMapper.xml 中的配置:

<!--public void insertEmp(Employee employee);
    -->
    <insert id="insertEmp"parameterType="com.njf.mybatis.bean.Employee">insert into tbl_employee(`last_name`, `email`, `gender`)
        values(#{lastName}, #{email}, #{gender})
    </insert>

测试:

@Test
     public void testInsert() throwsIOException {
          //1、获取 sqlSessionFactory
          SqlSessionFactory sqlSessionFactory =getsqlSessionFactory();

          //2、获取 sqlSession 实例,能直接执行已经映射的 SQL 语句
          SqlSession sqlSession =sqlSessionFactory.openSession();
          try{
               EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);

               Employee employee = new Employee(null, "张三", "男", "zhangsan@126.com");
               mapper.insertEmp(employee);
               
               sqlSession.commit();
          } finally{
               sqlSession.close();
          }
     }

运行结果:

MyBatis(四)映射文件 之 参数获取详解#{} 与 ${}第1张

  2、${} 取值

修改 mapper.xml 中的配置如下:

<!--public void insertEmp(Employee employee);
    -->
    <insert id="insertEmp"parameterType="com.njf.mybatis.bean.Employee">insert into tbl_employee(`last_name`, `email`, `gender`)
        values(${lastName}, ${email}, ${gender})
    </insert>

运行结果:

MyBatis(四)映射文件 之 参数获取详解#{} 与 ${}第2张

可以发现这时并没有运行成功,这条 SQL 语句与数据库的类型不匹配。

再次修改 mapper.xml,给 ${} 加上单引号

<!--public void insertEmp(Employee employee);
    -->
    <insert id="insertEmp"parameterType="com.njf.mybatis.bean.Employee">insert into tbl_employee(`last_name`, `email`, `gender`)
        values('${lastName}', '${email}', '${gender}')
    </insert>

运行结果:

MyBatis(四)映射文件 之 参数获取详解#{} 与 ${}第3张

此时就可以运行成功了。

  3、总结

获取参数值有两种方式:#{}与${}
(1)#{}
这种方式获取值,执行SQL时,是使用PreparedStatement,使用 ?(通配符)来赋值的
这种方式对于字符串类型来说,会自动加上单引号,不需要手动加单引号
因为在为 String 赋值时,可以自动加单引号,不需要考虑单引号
好处:可以防止SQL注入,更加安全。
(2)${}
这种方式获取值,执行SQL时,使用Statement对象,不能使用通配符赋值,只能使用字符串拼接方式来赋值。
对于字符串类型,不会自动加单引号,需要手动加!!!
注意:这种方式使用字符串拼接的方式操作SQL语句,一定要注意单引号问题!!!
使用建议:
建议优先使用 #{},在特殊情况,再使用 ${}。(例如:模糊查询、批量删除等操作时)
原生jdbc不支持占位符的地方我们就可以使用${}进行取值
比如分表、排序。。。;按照年份分表拆分
select * from ${year}_salary where xxx;                //按年份表查询
select * from tbl_employee order by ${f_name} ${order} //排序
三、不同的参数类型,#{}与 ${}的不同取值方式

  1、当传输参数为单个String或基本数据类型和其包装类时

(1)#{}可以以任意的名字获取参数值

在接口中声明方法:

public Employee getEmployeeById(Integer id);

在对应的映射文件中配置:

<!--public Employee getEmployeeById(Integer id);
    -->
    <select id="getEmployeeById"resultType="Employee">select id, last_name lastName, email, gender from tbl_employee where id = #{id}
    </select>

运行结果:

MyBatis(四)映射文件 之 参数获取详解#{} 与 ${}第4张

如果修改了Mapper.xml中的名字呢,还可以获取参数吗?

<!--public Employee getEmployeeById(Integer id);
    -->
    <select id="getEmployeeById"resultType="Employee">select id, last_name lastName, email, gender from tbl_employee where id = #{aaa}
    </select>

运行结果:

MyBatis(四)映射文件 之 参数获取详解#{} 与 ${}第5张

可以看出,修改了SQL语句中的参数名字,也可以获取参数并赋值成功!

(2)${}只能以 ${value}或 ${_parameter}获取

mapper.xml 中的配置信息以 ${value} 取值

<!--public Employee getEmployeeById(Integer id);
    -->
    <select id="getEmployeeById"resultType="Employee">select id, last_name lastName, email, gender from tbl_employee
        where id = ${value}
    </select>

第一次运行结果:

MyBatis(四)映射文件 之 参数获取详解#{} 与 ${}第6张

修改 mapper.xml 中的配置为:${_parameter}

<!--public Employee getEmployeeById(Integer id);
    -->
    <select id="getEmployeeById"resultType="Employee">select id, last_name lastName, email, gender from tbl_employee
        where id = ${_parameter}
    </select>

第二次运行结果:

MyBatis(四)映射文件 之 参数获取详解#{} 与 ${}第7张

如果修改 mapper.xml中的配置为 ${id} 呢?

<!--public Employee getEmployeeById(Integer id);
    -->
    <select id="getEmployeeById"resultType="Employee">select id, last_name lastName, email, gender from tbl_employee
        where id = ${id}
    </select>

运行结果:

MyBatis(四)映射文件 之 参数获取详解#{} 与 ${}第8张

运行失败了!

如果再改成随意的一个名字呢?

<!--public Employee getEmployeeById(Integer id);
    -->
    <select id="getEmployeeById"resultType="Employee">select id, last_name lastName, email, gender from tbl_employee
        where id = ${aaa}
    </select>

运行结果:

MyBatis(四)映射文件 之 参数获取详解#{} 与 ${}第9张

还是运行失败!

所以,对于${}获取单个参数,只能使用 ${value}或 ${_parameter}

  2、当传输参数为JavaBean时

#{}和 ${}都可以通过属性名直接获取属性值。
但是一定要注意 ${}的单引号问题。
参照上面的insert操作。

  3、当传输多个参数时(不用考虑类型)

当传输多个参数时,MyBatis会默认将这些参数放到Map集合中。

有两种方式来实现:

① 存储时键为:0,1,2,3,... N-1,值就是参数本身

② 存储时键为:param1,param2,param3...paramN,值是参数本身。

注意:每个参数都是有顺序的,获取和存放都是有顺序的。(内部用SortedMap来实现)

1、#{} 取值

有两种方式:

① 使用 #{0},#{1} 来依次获取参数;

② 使用#{param1}, #{param2},#{paramN} 依次来获取参数

mapper 的映射文件中以 #{N} 来获取参数

<!--public Employee getEmployeeByIdAndLastName(Integer id, String name);
    -->
    <select id="getEmployeeByIdAndLastName"resultType="Employee">select id, last_name lastName, email, gender from tbl_employee where id =  #{0} and last_name = #{1}
    </select>

运行结果:

MyBatis(四)映射文件 之 参数获取详解#{} 与 ${}第10张

mapper 的映射文件中以 #{paramN} 来获取参数

<!--public Employee getEmployeeByIdAndLastName(Integer id, String name);
    -->
    <select id="getEmployeeByIdAndLastName"resultType="Employee">
        <!--select id, last_name lastName, email, gender from tbl_employee where id =  #{0} and last_name = #{1}-->select id, last_name lastName, email, gender from tbl_employee where id =  #{param1} and last_name = #{param2}
    </select>

运行结果:

MyBatis(四)映射文件 之 参数获取详解#{} 与 ${}第11张

2、${} 取值

有一种方式:使用 ${param1},${param2}依次来获取参数,但是要注意 ${}的单引号问题!!!

(1)Mapper.xml中以 ${paramN}来获取参数

映射文件:

<!--public Employee getEmployeeByIdAndLastName(Integer id, String name);
    -->
    <select id="getEmployeeByIdAndLastName"resultType="Employee">select id, last_name lastName, email, gender from tbl_employee where id =  ${param1} and last_name = ${param2}
    </select>

运行结果:

MyBatis(四)映射文件 之 参数获取详解#{} 与 ${}第12张

并没有成功,对于String类型忘记加单引号了!!!

给String类型加上单引号后:

<!--public Employee getEmployeeByIdAndLastName(Integer id, String name);
    -->
    <select id="getEmployeeByIdAndLastName"resultType="Employee">select id, last_name lastName, email, gender from tbl_employee where id =  ${param1} and last_name = '${param2}'
    </select>

运行结果:

MyBatis(四)映射文件 之 参数获取详解#{} 与 ${}第13张

此时就可以运行成功了。

(2)Mapper.xml中以 ${0}来获取参数

映射文件配置:

<!--public Employee getEmployeeByIdAndLastName(Integer id, String name);
    -->
    <select id="getEmployeeByIdAndLastName"resultType="Employee">select id, last_name lastName, email, gender from tbl_employee where id =  ${0} and last_name = ${1}
    </select>

运行结果:

MyBatis(四)映射文件 之 参数获取详解#{} 与 ${}第14张

可以发现这种方式并不能正确获取参数。

那如果给String类型加上单引号,应该也是不可以的。

加上单引号后,以 '${0}'来获取参数

<!--public Employee getEmployeeByIdAndLastName(Integer id, String name);
    -->
    <select id="getEmployeeByIdAndLastName"resultType="Employee">select id, last_name lastName, email, gender from tbl_employee where id =  ${0} and last_name = '${1}'
    </select>

运行结果:

MyBatis(四)映射文件 之 参数获取详解#{} 与 ${}第15张

这种也不可以获取参数。

对于${} 取值的方式,所以只能使用 ${paramN}的方式来获取参数。

  4、当传输自定义的Map参数时

#{}和 ${}都可以通过键的名字直接获取属性值,但是要注意对于String类型 ${} 取值的单引号问题!!!
接口中的方法:
public Employee getEmployeeByMap(Map<String, Object> map);
映射文件中的配置以 #{key} 的方式取值:
<!--public Employee getEmployeeByMap(Map<String, Object> map);
    -->
    <select id="getEmployeeByMap"resultType="Employee">select id, last_name lastName, email, gender from tbl_employee where id =  #{id} and last_name = #{lastName}
    </select>
测试:
@Test
     public void test() throwsIOException {
          //1、获取 sqlSessionFactory
          SqlSessionFactory sqlSessionFactory =getsqlSessionFactory();

          //2、获取 sqlSession 实例,能直接执行已经映射的 SQL 语句
          SqlSession sqlSession =sqlSessionFactory.openSession();
          try{
               EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);

               Map<String, Object> map = new HashMap<>();
               map.put("id", "1");           //这里的 key 需要与 xml 中的 key 一致
               map.put("lastName", "Tom");      //这里的 key 需要与 xml 中的 key 一致
               Employee emp =mapper.getEmpByMap(map);

               System.out.println("emp = " +emp);
          } finally{
               sqlSession.close();
          }
     }
运行结果:
MyBatis(四)映射文件 之 参数获取详解#{} 与 ${}第16张
映射文件中的配置以 ${key} 的方式取值:
<!--public Employee getEmployeeByMap(Map<String, Object> map);
    -->
    <select id="getEmployeeByMap"resultType="Employee">select id, last_name lastName, email, gender from tbl_employee where id =  ${id} and last_name = '${lastName}'
    </select>
运行结果:
MyBatis(四)映射文件 之 参数获取详解#{} 与 ${}第17张

  5、命名参数

可以通过 @Param("key")为map集合指定键的名字,也可以使用 #{paramN}的方式来取值

Mapper 接口中的方法:

public Employee  getEmpByIdAndEnameByParam(@Param("id") int id, @Param("lastName")String lastName);

Mapper.xml 中的配置以 #{key} 来取值:

<!--public Employee  getEmpByIdAndEnameByParam(@Param("id")String id,  @Param("lastName")String lastName);
    -->
    <select id="getEmpByIdAndEnameByParam"resultType="Employee">select id, last_name lastName, email, gender from tbl_employee where id =  #{id} and last_name = #{lastName}
    </select>

运行结果:

MyBatis(四)映射文件 之 参数获取详解#{} 与 ${}第18张

Mapper.xml中的配置以 ${key}来取值

<!--public Employee  getEmpByIdAndEnameByParam(@Param("id")String id,  @Param("lastName")String lastName);
    -->
    <select id="getEmpByIdAndEnameByParam"resultType="Employee">select id, last_name lastName, email, gender from tbl_employee where id =  ${id} and last_name = '${lastName}'
    </select>

运行结果:

MyBatis(四)映射文件 之 参数获取详解#{} 与 ${}第19张

切记:String类型的 ${key}的方式取值一定要加单引号!!!

  6、当传输的是Collection/Array时

Collection/Array 会被MyBatis封装成一个map传入,Collection对应的 key是collection,Array对应的 key是array,如果确定是List集合,key还可以是list。

四、#{} 更丰富的用法

  1、参数位置支持的属性

规定参数的一些规则:

javaType、 jdbcType、 mode(存储过程)、 numericScale、resultMap、 typeHandler、 jdbcTypeName、 expression(未来准备支持的功能);

  2、jdbcType通常需要在某种特定的条件下被设置

在我们数据为null的时候,有些数据库可能不能识别mybatis对null的默认处理。比如Oracle(报错);
JdbcType
OTHER:无效的类型;因为mybatis对所有的null都映射的是原生Jdbc的OTHER类型,oracle不能正确处理;
由于全局配置中:jdbcTypeForNull=OTHER;oracle不支持;两种办法
        1、#{email,jdbcType=NULL};
        2、jdbcTypeForNull=NULL
            <setting name="jdbcTypeForNull" value="NULL"/>

实际上通常被设置的是:可能为空的列名指定 jdbcType
insert into orcl_employee(id,last_name,email,gender)
values(employee_seq.nextval,#{lastName,jdbcType=NULL },#{email},#{gender})

  3、参数处理

参数也可以指定一个特殊的数据类型:

#{property, javaType=int, jdbcType=NUMERIC}
#{height, javaType=double, jdbcType=NUMERIC, numericScale=2}

javaType 通常可以从参数对象中来去确定;

如果 null 被当作值来传递,对于所有可能为空的列,jdbcType 需要被设置;

对于数值类型,还可以设置小数点后保留的位数;

mode 属性允许指定 IN, OUT 或 INOUT 参数。如果参数为 OUT 或 INOUT,参数对象属性的真实值将会被改变,就像在获取输出参数时所期望的那样。

免责声明:文章转载自《MyBatis(四)映射文件 之 参数获取详解#{} 与 ${}》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇SQL Server 检测到基于一致性的逻辑 I/O 错误 页撕裂Golang: 解析JSON数据之一下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

poi解析office文档内容的工具类

第一步引入依赖 <!--xls--> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId>...

Java进程CPU100%的问题

今天review了一下测试环境,后来发现一个java进程CPU 120%多,4核的CPU,很多人都没感觉。但是确实是很大问题。测试环境没什么并发,也没什么数据量怎么会这么高的cpu呢? 找到java进程中耗cpu最高的nid, top –p pid –H 用jstack或者其他方式打印一下线程堆栈,从堆栈记录里找出nid,对应的线程和他的堆栈。找到出问题...

MySQL 中随机抽样:order by rand limit 的替代方案

  最近由于需要大概研究了一下MYSQL的随机抽取实现方法。举个例子,要从tablename表中随机提取一条记录,大家一般的写法就是:SELECT * FROM tablename ORDER BY RAND() LIMIT 1。       但是,后来我查了一下MYSQL的官方手册,里面针对RAND()的提示大概意思就是,在ORDER BY从句里面不能使...

JAVA MyBatis配置文件用properties引入外部配置文件

方式一:通过properties 元素的子元素来传递数据 例如: 1 <properties> 2 <property name="driver" value="com.mysql.jdbc.Driver" /> <!-- 驱动类型 --> 3 <property nam...

MySQL的多表查询(笛卡尔积原理)

先确定数据要用到哪些表。 将多个表先通过笛卡尔积变成一个表。 然后去除不符合逻辑的数据(根据两个表的关系去掉)。 最后当做是一个虚拟表一样来加上条件即可。 注意:列名最好使用表别名来区别。 笛卡尔积 Demo: 左,右连接,内,外连接 l 内连接: 要点:返回的是所有匹配的记录。 2. select * from a,b where a.x =...

easyexcel导出两种方式response返回文件流下载和保存到服务器返回下载链接

1、response方式返回excel文件流 @GetMapping("/exportExcel") public void exportExcel(@RequestParam(value = "menu") String menu, @RequestParam(value = "dwflgl...