前言
思考一个问题,前面的#{}和${}的区别中,我们知道了#{},MyBatis底层调用的是preparestatement这种预编译的方式,这种方式sql语句会预先编程 select * from t_user where id = ?这种形式,随后调用setInt(),setString(),…等方法为?赋值,但是myBatis是怎样知道参数是什么类型呢?这个就是MyBatis的动态推理了。具体是怎样推理的我们不再讨论,接下来我们讨论有哪些数据类型,MyBatis可以动态推理出来。
接下来通过各种查询来测试
准备工作
简单数据类型且只有一个参数
String
接口中方法
/***
* 通过姓名来查询
* @param id
* @return
*/
List<Student> selectById(Long id);
Sql映射文件中代码(完整写法,告诉MyBatis我们的参数是什么类型的)
<select id="selectByName" resultType="Student" parameterType="java.lang.String">
select * from t_student where name = #{name}
</select>
测试代码
@Test
public void testSelectByName(){
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = mapper.selectByName("张三");
for (Student s : students){
System.out.println(s);
}
sqlSession.close();
}
测试结果
可以看出可以正常的查出来
缺省一下parameterType
<select id="selectByName" resultType="Student">
select * from t_student where name = #{name}
</select>
再次运行结果
可以看出MyBatis可以正确地推导出参数类型
java.util.Date
接口中方法
/***
* 根据birth查询
* @param birth
* @return
*/
List<Student> selectByBirth(Date birth);
sql语句映射文件中代码(缺省版)
<select id="selectByBirth" resultType="Student">
select * from t_student where birth = #{birth}
</select>
测试代码
@Test
public void testSelectByBirth() throws ParseException {
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date birth = sdf.parse("1998-02-12");
List<Student> students = mapper.selectByBirth(birth);
for (Student s : students){
System.out.println(s);
}
sqlSession.close();
}
测试结果
可以看出,Date类型也可以缺省
具体都有哪些简单数据类型可以缺省呢?
经测试以下类型都可以缺省
byte short int long float double char
Byte Short Integer Long Float Double Character
String
java.util.Date
就不一一测试了
Map参数
接口中代码
/***
* 根据姓名和年龄来查询
* @param map
* @return
*/
List<Student> selectByNameAndAge(Map<String, Object> map);
Sql映射文件中代码(缺省版本)
<select id="selectByNameAndAge" resultType="Student">
select * from t_student where name = #{sname} and age = #{sage}
</select>
注意#{}中的值必须是map中的键值
测试代码
@Test
public void testSelectByNameAndAge(){
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Map<String, Object> map = new HashMap<>();
map.put("sname","张三");
map.put("sage",20);
List<Student> students = mapper.selectByNameAndAge(map);
for(Student s : students)
System.out.println(s);
sqlSession.close();
}
运行结果
得出结论Map也可以缺省
实体类参数
接口中代码
/***
* 保存学生信息
* @param s
* @return
*/
int insert(Student s);
Sql映射文件中代码(缺省parameterType)
<insert id="insert">
insert into t_student values(null,#{name},#{age},#{height},#{birth},#{sex})
</insert>
测试代码
@Test
public void testInsert(){
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Student student = new Student(null, "赵六", 18, 1.7, new Date(), '男');
int count = mapper.insert(student);
System.out.println(count);
sqlSession.commit();
sqlSession.close();
}
运行结果
可以看出参数是实体类的时候也是可以缺省的
多个参数的情况
接口中代码
/***
* 通过姓名和性别来进行查询
* @param name
* @param sex
* @return
*/
List<Student> selectByNameAndSex(String name,Character sex);
Sql映射文件中代码(缺省参数类型)
<select id="selectByNameAndSex" resultType="Student">
select * from t_student where name = #{name} and sex = #{sex}
</select>
测试代码
@Test
public void testSelectByNameAndSex(){
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = mapper.selectByNameAndSex("张三", '男');
for(Student s : students)
System.out.println(s);
sqlSession.close();
}
测试结果
可以看出运行出现了问题,提醒参数name没有找到,并且提醒可用的参数为[arg1, arg0, param1, param2]
更改Sql映射文件中的代码为如下
<select id="selectByNameAndSex" resultType="Student">
select * from t_student where name = #{arg0} and sex = #{arg1}
</select>
再次运行结果为
将文件更改为
<select id="selectByNameAndSex" resultType="Student">
select * from t_student where name = #{param1} and sex = #{param2}
</select>
也可以通过
结论
可以看出当参数有多个的时候,MyBatis已经为我们起好了参数名,我们需要正确地使用MyBatis为我们准备好的参数名
arg0 是第⼀个参数
param1是第⼀个参数
arg1 是第⼆个参数
param2是第⼆个参数
实现原理:实际上在mybatis底层会创建⼀个map集合,以arg0/param1为key,以⽅法上的参数为 value
例如如下代码
Map<String,Object> map = new HashMap<>();
map.put("arg0", name);
map.put("arg1", sex);
map.put("param1", name);
map.put("param2", sex);
// 所以可以这样取值:#{arg0} #{arg1} #{param1} #{param2}
// 其本质就是#{map集合的key}
注意:使⽤mybatis3.4.2之前的版本时:要⽤#{0}和#{1}这种形式。
疑问:我们必须使用MyBatis为我们准备的参数吗? @Param注解登场
@Param注解(命名参数)
如果我们不想使用系统提供的参数名,我们可以自己规定吗?答案是肯定的
我们可以使用@Param来为参数起名字(也就是底层Map中参数对应的key值名)
实战
接口中的代码
/***
* 通过姓名和性别来进行查询
* @param name
* @param sex
* @return
*/
List<Student> selectByNameAndSex(@Param(value = "name") String name,@Param("sex") Character sex);
value = 可以省略
更改Sql映射文件中的代码
<select id="selectByNameAndSex" resultType="Student">
select * from t_student where name = #{name} and sex = #{sex}
</select>
再次运行刚才的测试代码
运行结果
可以看出我们的@Param起作用了
核心:@Param(“这⾥填写的其实就是map集合的key”)
希望通过这篇文章大家都可以对MyBatis中的参数有一个更加深的理解