详解Mybatis之参数传递问题

文章详细介绍了Mybatis中参数传递的各种方式,包括单个普通参数、多个参数、命名参数、POJO参数、Map参数以及Collection、List和Array参数的传递。同时,讨论了#与$在参数绑定中的区别,#用于预编译的PreparedStatement,提供安全性,而$则直接替换在SQL中,可能存在SQL注入风险。
摘要由CSDN通过智能技术生成

编译软件:IntelliJ IDEA 2019.2.4 x64
操作系统:win10 x64 位 家庭版
Maven版本:apache-maven-3.6.3
Mybatis版本:3.5.6



一. Mybatis中参数传递问题

1.1 单个普通参数传递

对于单个普通参数而言,只要它的数据类型是Java基本数据类型,包装类型,字符串类型等。请放心大胆的使用它去传递,因为MyBatis可直接使用这个参数,不需要经过任何处理。且不受参数名称约束,即你可以任意命名,但一般遵循见名知意的原则。

示例代码如下:

<select id="selectUsers" resultType="User">
  select id, username, password
  from users
  where id = #{id}
</select>

在上述代码中,"#{id}"中的id可以任意取名,并且在程序中传给id的参数,其数据类型只要是符合(Java基本数据类型,包装类型,字符串类型)其中之一,MyBatis可直接使用这个参数传入到sql语句中。

1.2 多个普通参数传递

对于任意多个参数而言,都会被MyBatis重新包装成一个Map传入。Map的key是param1,param2,或arg0,arg1。相应的value是参数的值。

用法案例:根据员工姓名与薪资在数据库中查找相应的员工信息

①先在Mapper接口定义根据员工姓名与薪资查找相应的员工信息的方法

代码示例如下:

//根据员工姓名与员工薪资来查查找相应的员工
public Employee selectEmployeeByNameandSalary(String lastName,double salary);

②在映射文件中定义相关的sql

<select id="selectEmployeeByNameandSalary" resultType="mybatis.pojo.Employee">
    select
        id,
        last_name ,
        email,
        salary
    from
        tbl_employee
    where last_name=#{param1}
          and
          salary=#{param2}
</select>

③测试

@Test
public void test2(){
    try {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //通过SqlSessionFactory对象调用openSession();
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //获取EmployeeMapper的代理对象
        EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);

        Employee employee = employeeMapper.selectEmployeeByNameandSalary("李四", 9000);
        System.out.println(employee);

    } catch (IOException e) {
        e.printStackTrace();
    }
}

在这里插入图片描述

1.3 命名参数

语法:

@Param(value="参数名")
@Param("参数名")

位置:

在XXXMapper接口中方法的形参前面声明

注意:

  • 它的底层封装的是Map结构
  • 命名参数支持参数【param1,param2,…】,但不支持【arg0,arg1…】

示例代码:

①Mapper接口对应代码的书写

//根据员工姓名与员工薪资来查查找相应的员工
public List<Employee> showEmpByName(@Param("lName") String lastName,@Param("salary") double salary);

②接口对应的映射文件中书写的sql

版本一(参数不使用param1,param2):

<select id="showEmpByName" resultType="mybatis.pojo.Employee">
    select
    id,
        last_name ,
        email,
        salary
    from
        tbl_employee
    //#{lName}里是Mapepr接口中对应方法形参中@Param("lName")里的值    
    where 
    	last_name=#{lName}
    and
        salary=#{salary}
</select>

版本二(参数使用param1,param2):

 <select id="showEmpByName" resultType="mybatis.pojo.Employee">
        select
            id,
            last_name ,
            email,
            salary
        from
            tbl_employee
        where
            last_name=#{param1}
        and
            salary=#{param2}
    </select>

版本三(参数使用arg0,arg1)

 <select id="showEmpByName" resultType="mybatis.pojo.Employee">
        select
        id,
            last_name ,
            email,
            salary
        from
            tbl_employee
        where
            last_name=#{arg0}
        and
            salary=#{arg1}
    </select>

③测试

	@Test
    public void test4(){
        try {
            //从当前类下寻找并加载mybatis-config.xml(核心配置文件)
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

            //通过SqlSessionFactory对象调用openSession()获取sqlsession对象
            SqlSession sqlSession = sqlSessionFactory.openSession();
            //sqlsession对象使用getMapper(),传入EmployeeMapper的反射对象以获取代理对象
            EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);

            //使用其代理对象调用showEmpByName()通过员工姓名与薪资去查找相应的员工
            List<Employee> jack = employeeMapper.showEmpByName("jack", 9000);
            System.out.println(jack);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

1.4 POJO(java Bean)参数传递

Mybatis支持POJO [Java Bean】入参,参数key是POjO中的属性

用法案例:基于1.2小结中的用法案例,修改Mapper接口中该方法的形参为Employee类型,仅修改映射文件中相应的sql与测试代码

①修改Mapper接口中该方法的形参类型为Employee

代码示例如下:

//根据员工姓名与员工薪资来查查找相应的员工
public Employee selectEmployeeByNameandSalary(Employee employee);

②修改映射文件中相应的sql

<select id="selectEmployeeByNameandSalary" resultType="mybatis.pojo.Employee">
    select
        id,
        last_name ,
        email,
        salary
    from
    	tbl_employee
    where 
    	last_name=#{lastName}
   and
    	salary=#{salary}
</select>

③测试

@Test
public void test3(){
    try {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //通过SqlSessionFactory对象调用openSession();
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //获取EmployeeMapper的代理对象
        EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);

        Employee employee=new Employee();
        employee.setSalary(5600.0);
        employee.setLastName("jack");

        Employee jack = employeeMapper.selectEmployeeByNameandSalary(employee);

        System.out.println(jack);

    } catch (IOException e) {
        e.printStackTrace();
    }
}

在这里插入图片描述

1.5 Map参数传递

Mybatis支持Map集合类型的元素直接入参,map的key是参数的key

注意:

Mybatis不支持方法重载,因为在Mybatis中xxxMapper接口对应的映射文件中若存在相同方法的sql,则其id值不能保持唯一性,会发生冲突

用法案例:基于1.2节的案例,这次使用Map集合作为形参传入,在对应的映射文件中书写相应的sql并测试

代码示例如下:

①使用Map集合作为形参传入

//根据员工姓名与员工薪资来查查找相应的员工
public List<Employee> showEmpByMap(Map<String,Object> map);

②在对应的映射文件中书写相应的sql

<select id="showEmpByMap" resultType="mybatis.pojo.Employee">
    select
        id,
        last_name ,
        email,
        salary
    from
    tbl_employee
    where last_name=#{lastName} and  salary=#{salary}
</select>

③测试

@Test
public void test5() {
    try {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //通过SqlSessionFactory对象调用openSession();
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //获取EmployeeMapper的代理对象
        EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);

        Map<String,Object> map=new HashMap<>();
        map.put("lastName","jack");
        map.put("salary",5600);

        List<Employee> jack = employeeMapper.showEmpByMap(map);
        System.out.println(jack);

    } catch (IOException e) {
        e.printStackTrace();
    }
}

在这里插入图片描述

1.6 Collection ,List & Array等参数传递

当传入的参数数据类型为 Collection ,List 或Array等,在对应映射文件的相应sql部分可直接使用mybatis对应的内置自定义类型别名(collection、list、array)传入,亦可使用命名参数自定义名称。

用法案例:通过多个id获取员工的信息 【EmpIds:员工id的集合】

代码示例如下:

a.在EmployeeMapper接口定义相应的方法

/**
 * 通过多个id获取员工的信息 【EmpIds:员工id的集合】
 * @param EmpIds
 * @return
 */
public List<Employee> selectEmpByIds(@Param("ids") List<Integer> EmpIds);

b.在EmployeeMapper接口对应的映射文件中定义相应的sql

 <select id="selectEmpByIds" resultType="employee">
        SELECT
            `id`,
            `last_name`,
            `email`,
            `salary`,
            `dept_id`
        FROM
            `tbl_employee`
        <where>
            `id` in
            (
            <foreach collection="ids" item="id" separator=",">
                #{id}
            </foreach>
            )
        </where>
    </select>

c.测试

@Test
public void test04(){
    try {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //通过SqlSessionFactory对象调用openSession();
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //获取EmployeeMapper的代理对象
        EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);

        List<Employee> employees = employeeMapper.selectEmpByOneOpr(1);
        System.out.println(employees);

    } catch (IOException e) {
        e.printStackTrace();
    }
}

在这里插入图片描述


二. Mybatis参数传递中#与$的使用问题

2.1 #与$的区别

  • #底层执行SQL语句的对象,使用PreparedStatementd,预编译SQL,防止SQL注入安全隐患,相对比较安全。
  • $底层执行SQL语句的对象使用Statementi对象,未解决SQL注入安全隐患,相对不安全。

2.2 #与$的使用场景

以查询SQL为例:

select col,col2 from table1 where col=? and col2=group by? order bylimit?,?

使用场景:

  • “#”使用场景:在上述Sql中的占位符位置均可以使用#
  • “$”使用场景:#解决不了的参数传递问题,均可以交给$处理【如form动态表格】

示例代码如下:

public List<Employee> selectEmpByDynamitTable(@Param("tblName")String tblName);
<select id="selectEmpByDynamitTable" resultType="employee">
	SELECT
        id,
        last_name,
        email,
        salary
	FROM
		${tb1Name}
</select>

附注:

在 Mybatis 中,$ 符号也是用于访问各种参数、变量等的值和信息的符号,主要用于动态 SQL 的构建和参数传递等场景中,例如:

  • ${variable}:用于插入变量或者表名/列名等的动态语句部分
  • #{parameter}:用于占位符参数的预编译语句
  • $方法名():用于调用 SQL 片段中定义的方法并返回结果

为什么说${variable}主要用于插入动态语句的部分?

解析不同:

  • ${variable}它是将传入的参数值直接显示在原来的sql语句中,且不加任何引号

    例如slect * from users where id= v a r i a b l e ,传入 {variable},传入 variable,传入{1} => id=1

    代码示例如下:

     <select id="showEmpByMap" resultType="mybatis.pojo.Employee">
            select
                id,
                last_name ,
                email,
                salary
            from
            tbl_employee
            where last_name=${lastName} and  salary=${salary}
        </select>
    
    

    在这里插入图片描述
    在这里插入图片描述

  • #{variable}是将传入的参数值当成一个字符串且加双引号显示

    例如slect * from users where id= v a r i a b l e ,传入 {variable},传入 variable,传入{1} => id=“1”

    代码示例如下:

     <select id="showEmpByMap" resultType="mybatis.pojo.Employee">
            select
                id,
                last_name ,
                email,
                salary
            from
            tbl_employee
            where last_name=#{lastName} and  salary=#{salary}
        </select>
    

    在这里插入图片描述

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

陌上少年,且听这风吟

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

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

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

打赏作者

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

抵扣说明:

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

余额充值