1. 多个参数 81
1.1 需求:通过name和sex查询 81
test中的com.powernode.mybatis.test
StudentMapperTest类中的testSelectByNameAndSex
//多个参数 81
@Test
public void testSelectByNameAndSex(){
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = mapper.selectByNameAndSex("张三", '男');
students.forEach(student -> System.out.println(student));
sqlSession.close();
}
StudentMapper.xml
<select id="selectByNameAndSex" resultType="Student">
<!--select * from t_student where name = #{name} and sex = #{age}-->
<!--select * from t_student where name = #{arg0} and sex = #{arg1}-->
<!--select * from t_student where name = #{param1} and sex = #{param2}-->
select * from t_student where name = #{arg0} and sex = #{param2}
</select>
1.2 通过测试可以看到:81
<select id="selectByNameAndSex" resultType="Student">
select * from t_student where name = #{name} and sex = #{age}
</select>
异常信息描述了:name参数找不到,可⽤的参数包括[arg1, arg0, param1, param2]
修改StudentMapper.xml配置⽂件:尝试使⽤[arg1, arg0, param1, param2]去参数
<select id="selectByNameAndSex" resultType="Student">
select * from t_student where name = #{arg0} and sex = #{arg1}
</select>
1.3 根据name和sex查询Student信息得到结论 81
* 如果是多个参数的话,mybatis框架底层是怎么做的呢?
* mybatis框架会自动创建一个Map集合。并且Map集合是以这种方式存储参数的:
* map.put("arg0", name);
* map.put("arg1", sex);
或者
* map.put("param1", name);
* map.put("param2", sex);
arg0 是第⼀个参数
param1是第⼀个参数
arg1 是第⼆个参数
param2是第⼆个参数
1.3.1 注意 81
低版本的mybatis中,使用的是:#{0}和#{1},以及#{2}...
高版本的mybatis中,使用的是:
#{arg0}
#{arg1}
#{arg2}
#{arg3}
#{arg4}
#{param1}
#{param2}
#{param3}
#{param4}
2. 参数之Param注解 82
可以不⽤arg0 arg1 param1 param2吗?这个map集合的key我们⾃定义可以吗?当然可以。使⽤@Param注解即可。这样可以增强可读性。
/**
* Param注解。 82
*
* mybatis框架底层的实现原理:
* map.put("name", name);
* map.put("sex", sex);
*
* @param name
* @param sex
* @return
*/
List<Student> selectByNameAndSex2(@Param("name") String name, @Param("sex") Character sex);
2.1 需求:根据name和age查询 82
test中的com.powernode.mybatis.test
StudentMapperTest类中的testSelectByNameAndSex2
//参数注解之Param 82
@Test
public void testSelectByNameAndSex2(){
SqlSession sqlSession = SqlSessionUtil.openSession();
// mapper实际上指向了代理对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
// mapper是代理对象
// selectByNameAndSex2是代理方法
List<Student> students = mapper.selectByNameAndSex2("张三", '男');
students.forEach(student -> System.out.println(student));
sqlSession.close();
}
StudentMapper.xml
<select id="selectByNameAndSex2" resultType="Student">
<!--使用了@Param注解之后,arg0和arg1失效了-->
<!--select * from t_student where name = #{arg0} and sex = #{arg1}-->
<!--使用了@Param注解之后,param1和param2还可以用-->
<!--select * from t_student where name = #{param1} and sex = #{param2}-->
select * from t_student where name = #{name} and sex = #{sex}
</select>
2.2 注意 82
使用了@Param注解之后,arg0和arg1失效了
select * from t_student where name = #{arg0} and sex = #{arg1}
使用了@Param注解之后,param1和param2还可以用
select * from t_student where name = #{param1} and sex = #{param2}
3. Param源码分析 83
4. 总代码
main中com.powernode.mybatis.mapper
StudentMapper
package com.powernode.mybatis.mapper;
import com.powernode.mybatis.pojo.Student;
import org.apache.ibatis.annotations.Param;
import java.util.Date;
import java.util.List;
import java.util.Map;
//mybatis参数处理 76
public interface StudentMapper {
/**
* Param注解。 82
*
* mybatis框架底层的实现原理:
* map.put("name", name);
* map.put("sex", sex);
*
* @param name
* @param sex
* @return
*/
List<Student> selectByNameAndSex2(@Param("name") String name, @Param("sex") Character sex);
/**
* 这是多参数。 81
* 根据name和sex查询Student信息。
* 如果是多个参数的话,mybatis框架底层是怎么做的呢?
* mybatis框架会自动创建一个Map集合。并且Map集合是以这种方式存储参数的:
* map.put("arg0", name);
* map.put("arg1", sex);
* map.put("param1", name);
* map.put("param2", sex);
*
* @param name
* @param sex
* @return
*/
List<Student> selectByNameAndSex(String name, Character sex);
/**
* 保存学生信息,通过POJO参数。Student是单个参数。但是不是简单类型。 80
* @param student
* @return
*/
int insertStudentByPOJO(Student student);
/**
* 保存学生信息,通过Map参数。以下是单个参数。但是参数的类型不是简单类型。是Map集合。79
* @param map
* @return
*/
int insertStudentByMap(Map<String, Object> map);
/**
* 当接口中的方法的参数只有一个(单个参数),并且参数的数据类型都是简单类型。 77-78
* 根据id查询、name查询、birth查询、sex查询
*/
List<Student> selectById(Long id);
List<Student> selectByName(String name);
List<Student> selectByBirth(Date birth);
List<Student> selectBySex(Character sex);
}
test中的com.powernode.mybatis.test
StudentMapperTest类
package com.powernode.mybatis.test;
//mybatis参数处理 76
import com.powernode.mybatis.mapper.StudentMapper;
import com.powernode.mybatis.pojo.Student;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 代理模式:
* 代理对象 链家
* 代理方法 找房子
* 目标对象 我
* 目标方法 找房子
*/
public class StudentMapperTest {
//参数注解之Param 82
@Test
public void testSelectByNameAndSex2(){
SqlSession sqlSession = SqlSessionUtil.openSession();
// mapper实际上指向了代理对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
// mapper是代理对象
// selectByNameAndSex2是代理方法
List<Student> students = mapper.selectByNameAndSex2("张三", '男');
students.forEach(student -> System.out.println(student));
sqlSession.close();
}
//多个参数 81
@Test
public void testSelectByNameAndSex(){
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = mapper.selectByNameAndSex("张三", '男');
students.forEach(student -> System.out.println(student));
sqlSession.close();
}
// POJO对象参数 80
@Test
public void testInsertStudentByPOJO(){
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
// POJO对象
Student student = new Student();
student.setName("张飞");
student.setAge(50);
student.setSex('女');
student.setBirth(new Date());
student.setHeight(10.0);
mapper.insertStudentByPOJO(student);
sqlSession.commit();
sqlSession.close();
}
//参数值Map集合 79
@Test
public void testInsertStudentByMap(){
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Map<String,Object> map = new HashMap<>();
map.put("姓名", "赵六");
map.put("年龄", 20);
map.put("身高", 1.81);
map.put("性别", '男');
map.put("生日", new Date());
mapper.insertStudentByMap(map);
sqlSession.commit();
sqlSession.close();
}
//当接口中的方法的参数只有一个(单个参数),并且参数的数据类型都是简单类型。 78
//根据sex查询
@Test
public void testSelectBySex(){
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
// char --> Character
Character sex = Character.valueOf('男');
List<Student> students = mapper.selectBySex(sex);
students.forEach(student -> System.out.println(student));
sqlSession.close();
}
//当接口中的方法的参数只有一个(单个参数),并且参数的数据类型都是简单类型。 78
//根据birth查询
// java.util.Date java.sql.Date,他们都是简单类型。
@Test
public void testSelectByBirth() throws Exception{
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//定义日期格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//根据日期格式写出日期(将"1980-10-11"字符串转成日期类型)
Date birth = sdf.parse("1980-10-11");
List<Student> students = mapper.selectByBirth(birth);
students.forEach(student -> System.out.println(student));
sqlSession.close();
}
//当接口中的方法的参数只有一个(单个参数),并且参数的数据类型都是简单类型。 78
//根据name查询
@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();
}
//当接口中的方法的参数只有一个(单个参数),并且参数的数据类型都是简单类型。 77
//根据id查询
@Test
public void testSelectById(){
SqlSession sqlSession = SqlSessionUtil.openSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = mapper.selectById(1L);
students.forEach(student -> System.out.println(student));
sqlSession.close();
}
}
main中com.powernode.mybatis.utils
工具类Utils
package com.powernode.mybatis.utils;
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 java.io.IOException;
/**
* MyBatis工具类
* @author 动力节点
* @version 1.0
* @since 1.0
*/
public class SqlSessionUtil {
private SqlSessionUtil(){}
private static SqlSessionFactory sqlSessionFactory;
static {
try {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// 全局的,服务器级别的,一个服务器当中定义一个即可。
// 为什么把SqlSession对象放到ThreadLocal当中呢?为了保证一个线程对应一个SqlSession。
private static ThreadLocal<SqlSession> local = new ThreadLocal<>();
/**
* 获取会话对象。
* @return 会话对象
*/
public static SqlSession openSession(){
SqlSession sqlSession = local.get();
if (sqlSession == null) {
sqlSession = sqlSessionFactory.openSession();
// 将sqlSession对象绑定到当前线程上。
local.set(sqlSession);
}
return sqlSession;
}
/**
* 关闭SqlSession对象(从当前线程中移除SqlSession对象。)
* @param sqlSession
*/
public static void close(SqlSession sqlSession){
if (sqlSession != null) {
sqlSession.close();
// 注意移除SqlSession对象和当前线程的绑定关系。
// 因为Tomcat服务器支持线程池。也就是说:用过的线程对象t1,可能下一次还会使用这个t1线程。
local.remove();
}
}
}
main中com.powernode.mybatis.pojo
Student
package com.powernode.mybatis.pojo;
import java.util.Date;
//一个pojo 76
public class Student {
private Long id;
private String name;
private Integer age;
private Double height;
private Date birth;
private Character sex;
@Override
public String () {
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;
}
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;
}
public Student() {
}
}
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.powernode.mybatis.mapper.StudentMapper">
<select id="selectByNameAndSex2" resultType="Student">
<!--使用了@Param注解之后,arg0和arg1失效了-->
<!--select * from t_student where name = #{arg0} and sex = #{arg1}-->
<!--使用了@Param注解之后,param1和param2还可以用-->
<!--select * from t_student where name = #{param1} and sex = #{param2}-->
select * from t_student where name = #{name} and sex = #{sex}
</select>
<!--
注意:低版本的mybatis中,使用的是:#{0}和#{1},以及#{2}...
高版本的mybatis中,使用的是:
#{arg0}
#{arg1}
#{arg2}
#{arg3}
#{arg4}
#{param1}
#{param2}
#{param3}
#{param4}
-->
<select id="selectByNameAndSex" resultType="Student">
<!--select * from t_student where name = #{name} and sex = #{age}-->
<!--select * from t_student where name = #{arg0} and sex = #{arg1}-->
<!--select * from t_student where name = #{param1} and sex = #{param2}-->
select * from t_student where name = #{arg0} and sex = #{param2}
</select>
<!--<insert id="insertStudentByPOJO" parameterType="student">-->
<insert id="insertStudentByPOJO">
insert into t_student(id,name,age,sex,birth,height) values(null,#{name},#{age},#{sex},#{birth},#{height})
</insert>
<!--<insert id="insertStudentByMap" parameterType="map">-->
<insert id="insertStudentByMap">
insert into t_student(id,name,age,sex,birth,height) values(null,#{姓名},#{年龄},#{性别},#{生日},#{身高})
</insert>
<!--
List<Student> selectById(Long id);
List<Student> selectByName(String name);
List<Student> selectByBirth(Date birth);
List<Student> selectBySex(Character sex);
parameterType属性的作用:
告诉mybatis框架,我这个方法的参数类型是什么类型。
mybatis框架自身带有类型自动推断机制,所以大部分情况下parameterType属性都是可以省略不写的。
SQL语句最终是这样的:
select * from t_student where id = ?
JDBC代码是一定要给?传值的。
怎么传值?ps.setXxx(第几个问号, 传什么值);
ps.setLong(1, 1L);
ps.setString(1, "zhangsan");
ps.setDate(1, new Date());
ps.setInt(1, 100);
...
mybatis底层到底调用setXxx的哪个方法,取决于parameterType属性的值。
注意:mybatis框架实际上内置了很多别名。可以参考开发手册。
-->
<select id="selectById" resultType="Student" parameterType="long">
select * from t_student where id = #{id}
</select>
<select id="selectByName" resultType="student">
select * from t_student where name = #{name, javaType=String, jdbcType=VARCHAR}
</select>
<select id="selectByBirth" resultType="student">
select * from t_student where birth = #{birth}
</select>
<select id="selectBySex" resultType="student">
select * from t_student where sex = #{sex}
</select>
</mapper>
pom.xml
<?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.powernode</groupId>
<artifactId>course16</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
<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>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
</dependency>
</dependencies>
<properties>
<!-- 编译代码使用的jdk版本-->
<maven.compiler.source>1.8</maven.compiler.source>
<!-- 运行程序使用的jdk版本-->
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</project>
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"/>
<typeAliases>
<package name="com.powernode.mybatis.pojo"/>
</typeAliases>
<environments default="dev">
<environment id="dev">
<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.powernode.mybatis.mapper"/>
</mappers>
</configuration>
jdbc.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/powernode
jdbc.username=root
jdbc.password=lzl
logback.xml
<?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>[%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>