03【MyBatis参数深入】

"本文详细介绍了MyBatis中的参数(parameterType)和返回值(resultType)类型,包括单个参数、多个参数的处理,以及PoJo对象的使用。在处理多个参数时,MyBatis会将参数封装成Map,可以通过#{param1}
摘要由CSDN通过智能技术生成

三、MyBaits参数深入

  • parameterType: 输入参数。对应方法的形参。

  • resultType: 输出参数。表示方法的返回值类型。

3.1 parameterType输入参数

parameterType用于确定方法的形参,在mapper映射文件中,parameterType可写可不写;

3.1.1 传递单个参数

在传递单个参数时,mybatis不会做特殊处理,#{参数名/任意名}都可以取出参数值,

接口:

package com.dfbz.dao;

import com.dfbz.entity.Emp;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public interface EmpDao {
    Emp findById(Integer id);
}

dao接口映射:

传递的是基本数据类型和String时,#{}里面的内容可以随便填写,取得都是形参中的值

<!--主键查询-->
<select id="findById" parameterType="int" resultType="com.dfbz.entity.Emp">
    select * from emp where id=#{abc}
</select>

测试:

package com.dfbz.demo;

import com.dfbz.dao.EmpDao;
import com.dfbz.entity.Emp;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
public class Demo01_MyBatis_ParameterType测试 {

    InputStream is;
    SqlSessionFactory sessionFactory;
    SqlSession session;
    EmpDao empDao;

    @Before
    public void init() throws Exception{
        is = Resources.getResourceAsStream("MyBatisConfig.xml");
        sessionFactory = new SqlSessionFactoryBuilder().build(is);
        session = sessionFactory.openSession(true);
        empDao = session.getMapper(EmpDao.class);
    }

    @After
    public void close() throws Exception{
        session.close();
        is.close();
    }

    @Test
    public void test1() throws IOException {
        Emp emp = empDao.findById(1);
        System.out.println(emp);
    }
}

3.1.2 传递多个参数时

1)MyBatis提供的方式

MyBaits在传递多个参数时会特殊处理,多个参数会被封装成 一个map,key从#{param1}一直到#{paramN},或者使用索引#{arg0}一直到#{argN}

举例:创建dao接口,根据薪资范围查询

  • dao接口:
List<Emp> findBySalaryScope(Double minSalary,Double maxSalary);
List<Emp> findBySalaryScope2(Double minSalary,Double maxSalary);
  • 接口映射:
<select id="findBySalaryScope" resultType="com.dfbz.entity.Emp">

    <!--
        >、<等特殊字符需要转义
        #{param1}:获取的是形参的第1个值
        #{param2}:获取的是形参的第2个值
     -->
    select * from emp where salary &gt;= #{param1} and salary &lt;= #{param2}
</select>


<select id="findBySalaryScope2" resultType="com.dfbz.entity.Emp">

    <!--
        #{0}:获取的是形参的第1个值
        #{1}:获取的是形参的第2个值
     -->
    select * from emp where salary &gt;= #{arg0} and salary &lt;= #{arg1}
</select>
  • 测试类:
@Test
public void test2() throws IOException {
    List<Emp> empList1 = empDao.findBySalaryScope(6000.0, 7000.0);
    List<Emp> empList2 = empDao.findBySalaryScope2(6000.0, 7000.0);

    System.out.println(empList1);
    System.out.println(empList2);
}
2)使用@param注解
  • 接口:
/**
 * 使用@Param注解来确定参数名
 * @param minSalary
 * @param maxSalary
 * @return
 */
List<Emp> findBySalaryScope3(@Param("minSalary") Double minSalary, @Param("maxSalary")Double maxSalary);
  • 接口映射:
<select id="findBySalaryScope3" resultType="com.dfbz.entity.Emp">
    select * from emp where salary &gt;= #{minSalary} and salary &lt;= #{maxSalary}
</select>

3.1.3 CDATA批量转译

<!--CDATA区 批量转译(如果在xml中有很多特殊符号,可以使用这种方式批量转译。)-->
<select id="findBySalaryScope3" resultType="com.dfbz.entity.Emp">
<![CDATA[
    select * from emp where salary > #{minSalary} and salary < #{maxSalary} and name like #{emp.name}
    ]]>
</select>

3.1.4 传递PoJo对象

POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBean,pojo包装类型指的是一个对象里面又包含了另外一个对象。

查询需求: 按照薪资的范围查询员工姓张的员工。

  1. 自定义一个查询类:Condition
  2. Condition中里面维护了User对象、还有薪资的开始、结束字段。
1)定义Pojo对象
package com.dfbz.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author lscl
 * @version 1.0
 * @intro:
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Condition {
    private Emp emp;
    private Double minSalary;
    private Double maxSalary;
}
2)dao接口
// 根据条件查询
List<Emp> findByCondition(Condition condition);
3)接口映射
<!--
    &gt; :表示大于号,在编写SQL的时候需要转义
    &lt; :表示小于号
-->
<select id="findByCondition" parameterType="com.dfbz.entity.Condition" resultType="com.dfbz.entity.Emp">
    select * from emp where salary &gt; #{minSalary} and salary &lt; #{maxSalary} and name like #{emp.name}
</select>
4)测试
@Test
public void test3() throws IOException {

    Emp emp =new Emp();
    emp.setName("%张%");

    Condition condition=new Condition();
    // 设置emp
    condition.setEmp(emp);

    condition.setMinSalary(3000.0);
    condition.setMaxSalary(10000.0);

    // 根据条件查询
    List<Emp> empList = empDao.findByCondition(condition);

    empList.forEach(System.out::println);
}

3.2 resultType输出参数

3.2.1 简单类型

1)dao接口:
Long count();
2)接口映射:
<!--统计-->
<select id="count" resultType="java.lang.Long">
    select count(1) from emp
</select>
3)测试:
@Test
public void test4() throws IOException {

    Long count = empDao.count();
    System.out.println("查询到: " + count + "条记录");
}

3.2.2 PoJo类型

1)dao接口:
/**
 * 根据员工姓名模糊查询
 * @param name
 * @return
 */
List<Emp> findByNameLike(String name);
2)接口映射:
<!--
    parameterType:入参类型(方法形参)
    resultType:出参类型(方法返回值)
-->
<select id="findByNameLike" parameterType="java.lang.String" resultType="com.dfbz.entity.Emp">
    select * from emp where name like #{name}
</select>
3)测试:
@Test
public void test7() throws IOException {

    List<Emp> empList = empDao.findByNameLike("%小%");
    empList.forEach(System.out::println);
}

3.2.3 Map类型

1)dao接口:
// 根据id查询用户,结果集为hashmap
Map<String,Object> findUserMapById(Integer id);

// 查询所有用户,结果集为List<HashMap>
List<Map<String,Object>> findAllUserMap();
2)接口映射:
<!--根据id查询用户,结果集为hashmap-->
<select id="findUserMapById" resultType="HashMap">
    select * from emp where id=#{id}
</select>

<!--查询所有用户,结果集为List<HashMap>-->
<select id="findAllUserMap" resultType="HashMap">
    select * from emp
</select>
3)测试:
@Test
public void test6() throws IOException {

    Map<String, Object> userMap = empDao.findUserMapById(1);

    System.out.println(userMap);

    List<Map<String, Object>> userMapAll = empDao.findAllUserMap();
    System.out.println(userMapAll);
}

3.3 resultMap输出参数

前面通过resultType作为输出参数,可以把查询的结果,自动封装为对象。但是,有要求,数据库中的列名称,要与对象的属性一致。否则,不能正确封装数据。此时,可以使用resultMap解决; 设置列与属性的映射关系。

默认情况下,查询封装的结果集表的列名必须和属性名一模一样(默认情况下驼峰命名也不行)

可以在SqlMapConfig.xml配置文件中开启驼峰映射:

<settings>
    <!--日志配置-->
    <setting name="logImpl" value="STDOUT_LOGGING"/>
    <!--开启驼峰命名自动映射-->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

3.3.1 接口

List<Emp> findAllEmp();

3.3.2 接口映射

<!--
    resultMap 指定查询的结果与对象的属性的映射关系
      id 被其他查询引用的
      type 要封装的对象类型
      <id>  指定主键字段的映射
      <result> 非主键字段的映射
          property 对应Emp对象的属性
          column   对应查询的结果字段
-->
<resultMap id="empResultMap" type="com.dfbz.entity.Emp">
    <id property="id" column="id_"></id>
    <result property="name" column="name_"></result>
    <result property="age" column="age_"></result>
    <result property="salary" column="salary_"></result>
    <result property="addr" column="addr_"></result>
</resultMap>
<select id="findAllEmp" resultMap="empResultMap">
    select id id_,name name_,age age_,salary salary_,addr addr_ from emp
</select>

3.3.3 测试类

@Test
public void test8() throws IOException {

    List<Emp> empList = empDao.findAllEmp();
    for (Emp emp : empList) {
        System.out.println(emp);
    }
}

3.4 SQL注入问题

在MyBatis传值的过程中,除了可以使用#{}获取值之外,还可以使用${}获取值:

定义一个接口:

List<Emp> findByName2(String name);

接口映射:

<!--模糊查询,另外的写法-->
<!--${value} 固定的写法,value值不能该。-->
<!--实现方式:直接拼接字符串,不能防止sql注入-->
<select id="findByUsername2" parameterType="java.lang.String" resultType="com.dfbz.entity.Emp">
    select * from emp where name like '${value}'
</select>

注意:使用${}时,里面必须填写value;在新版本可以写任意的值

根据测试结果,不能防止sql注入。

// 不能防止SQL注入
List<Emp> empList = userDao.findByNameLike2("abc' or 1=1 -- ");

// 能防止SQL注入
List<Emp> empList = userDao.findByNameLike("abc' or 1=1 -- ");

3.5 #{}和${}的区别

既然#{}${}好那么多,那为什么还要有${}这个东西存在呢?干脆都用#{}不就万事大吉吗?其实不是的,${}也有用武之地;

  • 场景举例:
<!--表名不确定的,需要当做参数传递进来-->
<select id="test1" parameterType="java.lang.String" resultType="com.dfbz.entity.Emp">
    select * from ${value}
</select>

<!--连SQL语句都不确定的,需要当做参数传递进来-->
<select id="test1" parameterType="java.lang.String" resultType="com.dfbz.entity.Emp">
    ${value}
</select>
  • 测试代码:
@Test
public void test10() throws IOException {

    List<Emp> empList = empDao.test1("emp");
    for (Emp emp : empList) {
        System.out.println(emp);
    }
}


@Test
public void test11() throws IOException {

    List<Emp> empList = empDao.test1("select * from emp");
    for (Emp emp : empList) {
        System.out.println(emp);
    }
}

总结:

1)#{}会对特殊字符进行过滤,传递的参数不会参与SQL语句的生成。

2)${}不会对特殊字符进行过滤,传递的参数本就是用于参与SQL语句生成的,因此会出现SQL注入的问题

3)${}里面必须填写value(新版本已经改进),#{}随意

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

緑水長流*z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值