编译软件: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 by?limit?,?
使用场景:
“#”
使用场景:在上述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>