1 前言
MyBatis 的映射文件中,获取参数的方式主要有 #{} 和 ${}。
(1)#{} 与 ${} 的区别
- #{}:参数占位符,使用 PreparedStatement 方式操作 SQL,在为 String 类型变量赋值时,可以自动加单引号,有预编译,可以防止 SQL 注入;
- ${}:字符串替换,使用 Statement 方式操作 SQL,在为 String 类型变量赋值时,需要手动加单引号,没有预编译,不可以防止 SQL 注入;
一般建议使用 #{},但在模糊查询和批量删除时,建议使用 ${}。由于 #{} 会给 String 类型变量自动加单引号,导致在模糊查询和批量删除时出现的问题见→JdbcTemplate。
(2)#{} 与 ${} 获取参数的方法
传输参数个数与类型 | #{}获取参数方法 | ${}获取参数方法 |
---|---|---|
1. 单个字面量 | 可以用任意名字获取参数值,如:#{xxx} | 只能用${value}或${_parameter}获取 |
2. 单个JavaBean | 可以通过属性名直接获取属性值,如:#{sid} | 可以通过属性名直接获取属性值,如:${sid} |
3. 单个Map | 可以通过键的名字获取值,如:#{key1} | 可以通过键的名字获取值,如:${key1} |
4. 多个字面量 | MyBatis会默认将这些参数放入Map中,并以0,1,2,...或param1,param2,param3,...为键,如:#{0}、#{param1}等 | MyBatis会默认将这些参数放入Map中,并以param1,param2,param3,...为键,如:${param1} |
5. 多个字面量,被@Param("key")标注 | MyBatis会默认将这些参数放入Map中,并以param1,param2,param3,...或@Param("p_id")后的参数为键,如:#{param1}、#{p_id}等 | MyBatis会默认将这些参数放入Map中,并以param1,param2,param3,...或@Param("p_id")后的参数为键,如:${param1}、${p_id} |
6. List或Array | MyBatis会默认将List或Array放入Map中,并以list或array为键 | MyBatis会默认将List或Array放入Map中,并以list或array为键 |
注意:字面量是指 String 和基本数据类型及其封装类,4和5中同一个值被2个键指向,如5中 map 如下,param1 和 p_id 都指向1005,param2 和 p_name 都指向"孙七"。
{p_name=孙七, p_id=1005, param1=1005, param2=孙七}
2 实验环境
(1)导入 JAR 包
其中,前2个 jar 包下载地址见 → log4j-1.2.17.jar、 mybatis-3.4.1.jar,将 jar 包放入 lib 目录下,并选中所有 jar 包,右键,选择【Add to Build Path】。
(2) 工作目录
注意:src 和 conf 目录下的 com.mapper 包必须同名。
(3)配置文件
log4j.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<param name="Encoding" value="UTF-8" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L)\n" />
</layout>
</appender>
<logger name="java.sql">
<level value="debug" />
</logger>
<logger name="org.apache.ibatis">
<level value="info" />
</logger>
<root>
<priority value="debug" />
<appender-ref ref="STDOUT" />
</root>
</log4j:configuration>
注意:log4j.xml文件名不能随意更改。
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 设置或引入资源文件 -->
<properties resource="jdbc.properties"></properties>
<!-- 设置连接数据库的环境,default用于设置默认使用的数据库环境 -->
<environments default="mysql">
<!-- 设置某个具体的数据库环境 -->
<environment id="mysql">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!-- 引入映射文件 -->
<mappers>
<package name="com.mapper"/>
</mappers>
</configuration>
jdbc.properties
# K = V
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/users
jdbc.username=root
jdbc.password=0.
3 案例分析
首先在 MySQL 中创建数据库:users,再在此数据库中创建表:students,包含id(int)、name(varchar)和sex(varchar) 3个字段,其中,id 设置了自增,students 表中数据如下:
首先介绍下公共的文件,包含 Student.java、StudentMapper.java、Test.java,不同的是 StudentMapper.xml,将在各章节分别介绍。
Student.java
package com.bean;
public class Student {
private Integer id;
private String name;
private String sex;
public Student() {}
public Student(Integer id, String name, String sex) {
this.id = id;
this.name = name;
this.sex = sex;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", sex=" + sex + "]";
}
}
StudentMapper.java
package com.mapper;
import java.util.Map;
import org.apache.ibatis.annotations.Param;
import com.bean.Student;
public interface StudentMapper {
//1. 单个字面量
public Student getStudentById(Integer id);
//2. 单个JavaBean
public Student getStudentByBean(Student student);
//3. 单个Map
public Student getStudentByMap(Map<String,Object> map);
//4. 多个字面量
public Student getStudentByIdAndName(Integer id,String name);
//5. 多个字面量,被@Param("key")标注
public Student getStudentByParam(@Param("p_id")Integer id,@Param("p_name")String name);
}
Test.java
package com.test;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
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 com.bean.Student;
import com.mapper.StudentMapper;
public class Test {
public static void main(String[] args) throws IOException {
InputStream is=Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession=sqlSessionFactory.openSession(true); //自动提交事务
//getMapper:会通过动态代理动态生成StudentMapper的代理实现类
StudentMapper mapper=sqlSession.getMapper(StudentMapper.class);
//1. 单个字面量
Student student1=mapper.getStudentById(1001);
System.out.println(student1);
//2. 单个JavaBean
Student student=new Student(1002,"李四",null);
Student student2=mapper.getStudentByBean(student);
System.out.println(student2);
//3. 单个Map
Map<String,Object> map=new HashMap();
map.put("id", 1003);
map.put("name", "王五");
Student student3=mapper.getStudentByMap(map);
System.out.println(student3);
//4. 多个字面量
Student student4=mapper.getStudentByIdAndName(1004,"周六");
System.out.println(student4);
//5. 多个字面量,被@Param("key")标注
Student student5=mapper.getStudentByParam(1005,"孙七");
System.out.println(student5);
}
}
3.1 #{} 方式获取参数
StudentMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mapper.StudentMapper">
<!-- 1.单个字面量:public Student getStudentById(Integer id); -->
<select id="getStudentById" resultType="com.bean.Student">
select * from students where id = #{xxx}
</select>
<!-- 2.单个JavaBean:public Student getStudentByBean(Student student); -->
<select id="getStudentByBean" resultType="com.bean.Student">
select * from students where id = #{id} and name = #{name}
</select>
<!-- 3.单个Map:public Student getStudentByMap(Map<Integer,String> map); -->
<select id="getStudentByMap" resultType="com.bean.Student">
select * from students where id = #{m_id} and name = #{m_name}
</select>
<!-- 4.多个字面量:public Student getStudentByIdAndName(Integer id,String name); -->
<select id="getStudentByIdAndName" resultType="com.bean.Student">
select * from students where id = #{0} and name = #{1}
<!-- select * from students where id = #{param1} and name = #{param2} -->
</select>
<!-- 5.多个字面量,被@Param("key")标注:public Student getStudentByParam(@Param("sid")Integer id,@Param("sname")String name); -->
<select id="getStudentByParam" resultType="com.bean.Student">
select * from students where id = #{p_id} and name = #{p_name}
<!-- select * from students where id = #{param1} and name = #{param2} -->
</select>
</mapper>
控制台输出如下:
DEBUG 06-12 22:44:16,593 ==> Preparing: select * from students where id = ?
Student [id=1001, name=张三, sex=男]
DEBUG 06-12 22:44:16,638 ==> Preparing: select * from students where id = ? and name = ?
Student [id=1002, name=李四, sex=女]
DEBUG 06-12 22:44:16,639 ==> Preparing: select * from students where id = ? and name = ?
Student [id=1003, name=王五, sex=男]
DEBUG 06-12 22:44:16,641 ==> Preparing: select * from students where id = ? and name = ?
Student [id=1004, name=周六, sex=女]
DEBUG 06-12 22:44:16,645 ==> Preparing: select * from students where id = ? and name = ?
Student [id=1005, name=孙七, sex=男]
3.2 ${} 方式获取参数
StudentMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mapper.StudentMapper">
<!-- 1.单个字面量:public Student getStudentById(Integer id); -->
<select id="getStudentById" resultType="com.bean.Student">
select * from students where id = ${value}
<!-- select * from students where id = ${_parameter} -->
</select>
<!-- 2.单个JavaBean:public Student getStudentByBean(Student student); -->
<select id="getStudentByBean" resultType="com.bean.Student">
select * from students where id = ${id} and name = '${name}'
</select>
<!-- 3.单个Map:public Student getStudentByMap(Map<Integer,String> map); -->
<select id="getStudentByMap" resultType="com.bean.Student">
select * from students where id = ${m_id} and name = '${m_name}'
</select>
<!-- 4.多个字面量:public Student getStudentByIdAndName(Integer id,String name); -->
<select id="getStudentByIdAndName" resultType="com.bean.Student">
select * from students where id = ${param1} and name = '${param2}'
</select>
<!-- 5.多个字面量,被@Param("key")标注:public Student getStudentByParam(@Param("sid")Integer id,@Param("sname")String name); -->
<select id="getStudentByParam" resultType="com.bean.Student">
select * from students where id = ${p_id} and name = '${p_name}'
<!-- select * from students where id = ${param1} and name = '${param2}' -->
</select>
</mapper>
控制台输出如下:
DEBUG 06-12 22:52:30,543 ==> Preparing: select * from students where id = 1001
Student [id=1001, name=张三, sex=男]
DEBUG 06-12 22:52:30,594 ==> Preparing: select * from students where id = 1002 and name = '李四'
Student [id=1002, name=李四, sex=女]
DEBUG 06-12 22:52:30,597 ==> Preparing: select * from students where id = 1003 and name = '王五'
Student [id=1003, name=王五, sex=男]
DEBUG 06-12 22:52:30,600 ==> Preparing: select * from students where id = 1004 and name = '周六'
Student [id=1004, name=周六, sex=女]
DEBUG 06-12 22:52:30,604 ==> Preparing: select * from students where id = 1005 and name = '孙七'
Student [id=1005, name=孙七, sex=男]