1. MyBatis 参数上的处理的细节内容
文章目录
- 1. MyBatis 参数上的处理的细节内容
- 2. MyBatis 参数上的处理
- 3. 准备工作
- 4. 单个(一个)参数
- 4.1 单个(一个)简单类型作为参数
- 4.2 单个(一个) Map集合 作为参数
- 4.3 单个(一个) 实体类POJO作为参数
- 5. 多个参数
- 5.1 @Param注解(命名参数)
- 6. @Param 注解源码分析
- 7. 总结:
- 8. 最后:
2. MyBatis 参数上的处理
3. 准备工作
数据表结构的设计,数据表名为:t_student
t_student 表中的数据信息:
在pom.xml
文件当中配置相关的依赖的 jar 包如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.rainbowsea</groupId>
<artifactId>mybatis-005-crud-blog</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<!-- mybatis 的依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- 引入 logback的依赖,这个日志框架实现了slf4j 规范-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
</dependency>
</dependencies>
</project>
配置 logback 的配置文件,用于打印显示,我们的日志信息,方便我们查看我们的运行过程,效果。
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!--mybatis log configure-->
<logger name="com.apache.ibatis" level="TRACE"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
<!-- 日志输出级别,logback日志级别包括五个:TRACE < DEBUG < INFO < WARN < ERROR -->
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
</root>
</configuration>
配置 MyBatis 的核心配置文件,
<?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>
<!-- 起别名-->
<typeAliases>
<!-- 使用 <package> 还可以将这个包下的所有的类的全部自动起别名,别名就是简名,不区分大小写 -->
<package name="com.rainbowsea.mybatis.pojo"/>
</typeAliases>
<environments default="mybatis">
<environment id="mybatis">
<!-- MANAGED 没有用第三框架管理的话,都是会被提交的,没有事务上的管理了 -->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="MySQL123"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 这里也是可以使用 package 包名扫描,但是同样的:对应接口路径要一致,接口名一致-->
<package name="com.rainbowsea.mybatis.mapper"></package>
</mappers>
</configuration>
对照 tstudent 创建的ORM 映射的 Car 类
注意:在MyBatis 当中对应的ORM ,一般在框架里对应的 Bean实体类,一定要实现该 set 和 get 方法以及无参数构造方法,无法框架无法使用反射机制,进行操作 。
建议用包装类,这样可以防止 Null的问题,因为(简单类型 int num = null ,是不可以赋值为 null)的编译无法通过
package com.rainbowsea.mybatis.pojo;
import java.util.Date;
public class Student {
private Long id;
private String name;
private Integer age;
private Double height;
private Date birth;
private Character sex;
public Student() {
}
public Student(Long id, String name, Integer age, Double height, Date birth, Character sex) {
this.id = id;
this.name = name;
this.age = age;
this.height = height;
this.birth = birth;
this.sex = sex;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", height=" + height +
", birth=" + birth +
", sex=" + sex +
'}';
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Double getHeight() {
return height;
}
public void setHeight(Double height) {
this.height = height;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public Character getSex() {
return sex;
}
public void setSex(Character sex) {
this.sex = sex;
}
}
4. 单个(一个)参数
4.1 单个(一个)简单类型作为参数
简单类型包括:
- byte short int long float double char
- Byte Short Integer Long Float Double Character
- String
- java.util.Date
- java.sql.Date
需求:根据name查、根据id查、根据birth查、根据sex查。
第一个:根据 id 查记录
package com.rainbowsea.mybatis.mapper;
import com.rainbowsea.mybatis.pojo.Student;
import org.apache.ibatis.annotations.Param;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.Map;
public interface StudentMapper {
// 单个参数上的处理
/**
* 当接口中的方法的参数只有一个(单个参数),并且参数的数据类型都是简单类型
* 根据id查询,name查询,birth查询,sex查询
*/
List<Student> selectById(Long id);
}
编写向对应上的:SQL 映射文件的内容:
<?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">
<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.StudentMapper">
<!-- id 要是 namespace 对应接口上的方法名: -->
<!-- parameterType 属性的作用:
告诉mybatis框架,我这个方法的参数类型是什么类型的
mybatis 框架自身带有类型自动推断的机制,所以大部分情况下 parameterType 属性都是可以省略不写的。
select * from t_student where id = ?
ps.setLong(1,1L)
ps.setString(1,"张三")
ps.setDate(1,new Date())
ps.setInt(1,100)
...
mybatis 底层到底调用setXxx的哪个方法,取决于parameterType属性的值
注意: mybatis框架时间上内置了很多别名,可以参考开发手册
-->
<select id="selectById" resultType="Student" parameterType="java.lang.Long">
select id, name, age, height, birth, sex
from t_student
where id = #{id}
</select>
</mapper>
paramterType 属性的作用:
告诉mybatis框架,我这个方法的参数类型是什么类型的
mybatis 框架自身带有类型自动推断的机制,所以大部分情况下 parameterType 属性都是可以省略不写的。
select * from t_student where id = ?
ps.setLong(1,1L)
ps.setString(1,“张三”)
ps.setDate(1,new Date())
ps.setInt(1,100)
…
mybatis 底层到底调用setXxx的哪个方法,取决于parameterType属性的值
注意: mybatis框架时间上内置了很多别名,可以参考开发手册resultType 属性的作用:
指定 select 查询,返回的结果集,封装到哪里,哪个对象当中,这里由于前面我们做好了关于别名上的准备工作,所以这里我们可以直接有用别名(简名)
Java程序编程,运行测试:
package com.rainbowsea.mybatis.test;
import com.rainbowsea.mybatis.mapper.StudentMapper;
import com.rainbowsea.mybatis.pojo.Student;
import com.rainbowsea.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class TestStudentMapper {
@Test
public void testSelectById() {
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = mapper.selectById(2L);
students.forEach(student -> {
System.out.println(student);
});
sqlSession.close();
}
}
在MyBatis 框架当中 内置了很多的别名,可以参考开发手册https://mybatis.net.cn/configuration.html#typeHandlers。
其实对于Mybatis 框架来说,简单类型对于mybatis来说都是可以自动类型识别的:
在MyBatis 框架当中如下,为的类型被定义为简单类型
简单类型包括:
-
byte short int long float double char
-
Byte Short Integer Long Float Double Character
-
String
-
java.util.Date
-
java.sql.Date
-
也就是说对于mybatis来说,它是可以自动推断出ps.setXxxx()方法的。ps.setString()还是ps.setInt()。它可以自动推断。
如下,我们不指定所传的参数类型,依靠MyBatis 的自行推断的机制,自行推断。
根据birth查、根据sex查。
package com.rainbowsea.mybatis.mapper;
import com.rainbowsea.mybatis.pojo.Student;
import org.apache.ibatis.annotations.Param;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.Map;
public interface StudentMapper {
// 单个参数上的处理
/**
* 当接口中的方法的参数只有一个(单个参数),并且参数的数据类型都是简单类型
* 根据id查询,name查询,birth查询,sex查询
*/
List<Student> selectByBirth(Date birth);
List<Student> selectBySex(Character sex);
}
对应的SQL语句映射文件的编写
<?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">
<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.StudentMapper">
<select id="selectByBirth" resultType="Student">
select id, name, age, height, birth, sex
from t_student
where birth = #{birth}
</select>
<select id="selectBySex" resultType="Student">
select id, name, age, height, birth, sex
from t_student
where sex = #{sex}
</select>
</mapper>
Java程序测试,编写
根据 brith 查询
//java.util.Date; java.sql.Date 他们在mybatis当中都是为简单类型
@Test
public void testSelectByBrith() throws ParseException {
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date birth = simpleDateFormat.parse("2020-06-06");
List<Student> students = mapper.selectByBirth(birth);
students.forEach(student -> {
System.out.println(student);
});
sqlSession.close();
}
根据 sex 查询
public class TestStudentMapper {
@Test
public void testSelectBySex() {
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = mapper.selectBySex('男');
students.forEach(student ->
{
System.out.println(student);
});
sqlSession.close();
}
}
通过测试得知,简单类型对于mybatis来说都是可以自动类型识别的:
- 也就是说对于mybatis来说,它是可以自动推断出ps.setXxxx()方法的。ps.setString()还是ps.setInt()。它可以自动推断。
其实SQL映射文件中的配置比较完整的写法是:
<select id="selectByName" resultType="student" parameterType="java.lang.String">
select * from t_student where name = #{name, javaType=String, jdbcType=VARCHAR}
</select>
其中sql语句中的javaType,jdbcType,以及select标签中的parameterType属性,都是用来帮助mybatis进行类型确定的。不过这些配置多数是可以省略的。因为mybatis它有强大的自动类型推断机制。
- javaType:可以省略
- jdbcType:可以省略
- parameterType:可以省略
根据name查。使用完整写法:
package com.rainbowsea.mybatis.mapper;
import com.rainbowsea.mybatis.pojo.Student;
import org.apache.ibatis.annotations.Param;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.Map;
public interface StudentMapper {
// 单个参数上的处理
/**
* 当接口中的方法的参数只有一个(单个参数),并且参数的数据类型都是简单类型
* 根据id查询,name查询,birth查询,sex查询
*/
List<Student> selectByName(String name);
}
public interface StudentMapper {
// 单个参数上的处理
/**
* 当接口中的方法的参数只有一个(单个参数),并且参数的数据类型都是简单类型
* 根据id查询,name查询,birth查询,sex查询
*/
List<Student> selectByName(String name);
}
Java程序测试,编写
package com.rainbowsea.mybatis.test;
import com.rainbowsea.mybatis.mapper.StudentMapper;
import com.rainbowsea.mybatis.pojo.Student;
import com.rainbowsea.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
public class TestStudentMapper {
@Test
public void testSelectByName() {
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = mapper.selectByName("李华");
students.forEach(student ->
{
System.out.println(student);
});
sqlSession.close();
}
}
**如果参数只有一个的话,#{} 里面的内容就随便写了。对于 ${} 来说,注意加单引号。关于 #{} 与 ${}的区别的更多内容,大家可以移步至:✏️✏️✏️ **
4.2 单个(一个) Map集合 作为参数
需求:根据name和age查询
import com.rainbowsea.mybatis.pojo.Student;
import org.apache.ibatis.annotations.Param;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.Map;
public interface StudentMapper {
// 单个参数上的处理
/**
* 保存学生信息,通过Map参数,以下是单参数,但是参数类型不是简单类型,是Map集合
*/
int insertStudentByMap(Map<String, Object> map);
}
注意:这种方式是手动封装Map集合,将每个条件以 key 和 value 的形式存放到集合中。然后在使用的时候通过 #{map集合的key}来取值(#{} 中的值一定要是 map 集合当中的 key 值,不然是无法取到值的,这里我为了更加明显的突出这一点,使用了中文作为 map 集合当中的 key)。
@Test
public void testInsertStudentByMap() throws ParseException {
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Map<String, Object> map = new HashMap<>();
map.put("姓名","赵六");
map.put("年龄",20);
map.put("身高",1.83);
map.put("性别",'男');
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date birth = simpleDateFormat.parse("2020-09-09");
map.put("生日",birth);
mapper.insertStudentByMap(map);
sqlSession.commit();
sqlSession.close();
}
<?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">
<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.StudentMapper">
<insert id="insertStudentByMap" parameterType="map">
insert into t_student (id,name,age,sex,birth,height)
values (null,#{姓名},#{年龄},#{性别},#{生日},#{身高});
</insert>
</mapper>
java运行测试
4.3 单个(一个) 实体类POJO作为参数
需求:插入一条Student数据
package com.rainbowsea.mybatis.mapper;
import com.rainbowsea.mybatis.pojo.Student;
import org.apache.ibatis.annotations.Param;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.Map;
public interface StudentMapper {
// 单个参数上的处理
/**
* 保存学生信息,通过PoJO参数,Student是单个参数,但不是简单类型
* @param student
* @return
*/
int insertStudentByPOJO(Student student);
}
<?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">
<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.StudentMapper">
<insert id="insertStudentByPOJO" parameterType="Student">
insert into t_student (id,name,age,sex,birth,height)
values (null,#{name},#{age},#{sex},#{birth},#{height});
</insert>
</mapper>
这里需要注意的是:#{} 里面写的是属性名字。这个属性名其本质上是:set/get方法名去掉set/get之后的名字。
运行测试:
5. 多个参数
根据 name 和 sex 查询 Student 信息
如果是多个参数,mybatis 框架底层是怎么做的呢?
mybatis 框架会自动创建一个map集合,并且map集合是以
这种方式存储参数的
map.put(“arg0”,name)
map.put(“arg1”,sex)
map.put(“param1”,name)
map.put(“param2”,sex)
需求:通过name和sex查询
这里我们先就用 和我们参数名一样的 name, sex 使用传给 #{} 试试。
异常信息描述了:name参数找不到,可用的参数包括[arg1, arg0, param1, param2]
修改StudentMapper.xml配置文件:尝试使用[arg1, arg0, param1, param2]去参数
<?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">
<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.StudentMapper">
<!-- 多个参数-->
<select id="selectByNameAndSex" resultType="Student">
select id,name,age,height,birth,sex
from t_student
where name = #{arg0} and sex = #{arg1}
</select>
</mapper>
运行测试:
import com.rainbowsea.mybatis.mapper.StudentMapper;
import com.rainbowsea.mybatis.pojo.Student;
import com.rainbowsea.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TestStudentMapper {
/**
* 根据 name 和 sex 查询 Student 信息
* 如果是多个参数,mybatis 框架底层是怎么做的呢?
* mybatis 框架会自动创建一个map集合,并且map集合是以
* 这种方式存储参数的
* map.put("arg0",name)
* map.put("arg1",sex)
* map.put("param1",name)
* map.put("param2",sex)
*
*
*/
@Test
public void TestSelectByNameAndSex(){
SqlSession sqlSession = SqlSessionUtil.openSession();
// mapper 实际上指向了代理对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
// mapper是代理对象
// selectByNameAndSex是代理方法
List<Student> students = mapper.selectByNameAndSex("李华", '男');
students.forEach(student -> {
System.out.println(student);
});
sqlSession.close();
}
}
再将其改为 where name = #{param1} and sex = #{param2} 试试
<?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">
<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.StudentMapper">
<!-- 多个参数-->
<select id="selectByNameAndSex" resultType="Student">
select id,name,age,height,birth,sex
from t_student
where name = #{param1} and sex = #{param2}
</select>
<!-- where name = #{arg0} and sex = #{arg1}-->
<!-- where name = #{param1} and sex = #{param2}-->
</mapper>
改为 arg0 和 param2 混合使用:where name = #{arg0} and sex = #{param2}
运行也是成功的;
通过测试可以看到:
- 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}
根据 name 和 sex 查询 Student 信息
* 如果是多个参数,mybatis 框架底层是怎么做的呢?
* mybatis 框架会自动创建一个map集合,并且map集合是以
* 这种方式存储参数的
* map.put(“arg0”,name)
* map.put(“arg1”,sex)
* map.put(“param1”,name)
* map.put(“param2”,sex)
注意:使用mybatis3.4.2之前的版本时:要用#{0}和#{1}这种形式。
5.1 @Param注解(命名参数)
可以不用arg0 arg1 param1 param2吗?这个map集合的 key我们自定义可以吗?
当然可以。使用 @Param 注解即可。这样可以增强可读性。
如下:
直接将其定义在参数的位置上,由于 注解的值为 value 时,可以省略属性名
需求:通过name和sex查询
package com.rainbowsea.mybatis.mapper;
import com.rainbowsea.mybatis.pojo.Student;
import org.apache.ibatis.annotations.Param;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.Map;
public interface StudentMapper {
/**
* 使用Param注解
* mybatis框架底层的实现原理
* @param name
* @param sex
* @return
*/
List<Student> selectByNameAndSex2(@Param(value = "name") String name, @Param("sex") Character sex);
}
<?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">
<!--namespace 一定要是:对应的接口的全限定类名-->
<mapper namespace="com.rainbowsea.mybatis.mapper.StudentMapper">
<!-- 多个参数-->
<select id="selectByNameAndSex2" resultType="Student">
select id,name,age,height,birth,sex
from t_student
where name = #{name} and sex = #{sex}
</select>
<!-- where name = #{arg0} and sex = #{arg1}-->
<!-- where name = #{param1} and sex = #{param2}-->
<!-- 使用 @Param 注解
注意:使用了@Param注解之后,arg0和arg1失效了,
而 param1和 param2 还可以用
-->
</mapper>
注意:使用了@Param注解之后,arg0和arg1失效了,而 param1和 param2 还可以用
Java程序编写测试:
import com.rainbowsea.mybatis.mapper.StudentMapper;
import com.rainbowsea.mybatis.pojo.Student;
import com.rainbowsea.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TestStudentMapper {
/**
* 根据 name 和 sex 查询 Student 信息
* 如果是多个参数,mybatis 框架底层是怎么做的呢?
* mybatis 框架会自动创建一个map集合,并且map集合是以
* 这种方式存储参数的
* map.put("arg0",name)
* map.put("arg1",sex)
* map.put("param1",name)
* map.put("param2",sex)
*
*
*/
@Test
public void TestSelectByNameAndSex(){
SqlSession sqlSession = SqlSessionUtil.openSession();
// mapper 实际上指向了代理对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
// mapper是代理对象
// selectByNameAndSex是代理方法
List<Student> students = mapper.selectByNameAndSex2("李华", '男');
students.forEach(student -> {
System.out.println(student);
});
sqlSession.close();
}
}
注意的是:不仅select 查询中可以用 @Param ,其它的增删改查,涉及多个参数,自定义参数名的都可以使用 @Param 注解。
6. @Param 注解源码分析
下面我们进行 DeBug 调试看看。
7. 总结:
告诉mybatis框架,我这个方法的参数类型是什么类型的,mybatis 框架自身带有类型自动推断的机制,所以大部分情况下 parameterType 属性都是可以省略不写的。
其实对于Mybatis 框架来说,简单类型对于mybatis来说都是可以自动类型识别的:
在MyBatis 框架当中如下,为的类型被定义为简单类型
简单类型包括:
byte short int long float double char
Byte Short Integer Long Float Double Character
String
java.util.Date
java.sql.Date
也就是说对于mybatis来说,它是可以自动推断出ps.setXxxx()方法的。ps.setString()还是ps.setInt()。它可以自动推断。
其实SQL映射文件中的配置比较完整的写法是:
<select id="selectByName" resultType="student" parameterType="java.lang.String"> select * from t_student where name = #{name, javaType=String, jdbcType=VARCHAR} </select>
其中sql语句中的javaType,jdbcType,以及select标签中的parameterType属性,都是用来帮助mybatis进行类型确定的。不过这些配置多数是可以省略的。因为mybatis它有强大的自动类型推断机制。
- javaType:可以省略
- jdbcType:可以省略
- parameterType:可以省略
指定 select 查询,返回的结果集,封装到哪里,哪个对象当中。
对于特殊的(不是简单)类型,POJO是无法自行推断的出来的,需要我们指定比如(集合,POJO类等)
注意:这种方式是手动封装Map集合,将每个条件以 key 和 value 的形式存放到集合中。然后在使用的时候通过 #{map集合的key}来取值(#{} 中的值一定要是 map 集合当中的 key 值,不然是无法取到值的)。
传的是POJO类时,需要注意的是:#{} 里面写的是属性名字。这个属性名其本质上是:set/get方法名去掉set/get之后的名字。
多个参数:mybatis 框架会自动创建一个map集合,并且map集合是以
这种方式存储参数的
map.put(“arg0”,name)
map.put(“arg1”,sex)
map.put(“param1”,name)
map.put(“param2”,sex)
注意:使用mybatis3.4.2之前的版本时:要用#{0}和#{1}这种形式。
- 注意:使用了@Param注解之后,arg0和arg1失效了,而 param1和 param2 还可以用 。
- 注意的是:不仅select 查询中可以用 @Param ,其它的增删改查,涉及多个参数,自定义参数名的都可以使用 @Param 注解。
8. 最后:
“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”