09、参数处理

 

一、单个简单类型参数

🌔 1、简单类型参数都包括哪些?

  • byte short int long float double char
  • Byte Short Integer Long Float Double Character
  • String
  • java.util.Date
  • java.sql.Date

🌔 2、准备工作 【创建操作的表和相关pojo类】

(1)设计表 t_car
 
(2)填写两条简单的数据
 
(3)在 idea 中创建一个新模块 mybatis-007-param 【文件结构如下】
 
(3)SqlSessionUtil 工具类 【其余Student类创建等就不展开赘述了,可以在前一个章节copy】

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;

/**
 * @author Bonbons
 * @version 1.0
 */
public class SqlSessionUtil {

    private SqlSessionUtil(){

     }

    //定义一个SqlSession
    private static final SqlSessionFactory sqlSessionFactory;
    //在类加载的时候初始化SqlSessionFactory
    static {

        try {

            sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
        } catch (IOException e) {

            throw new RuntimeException(e);
        }
    }
    //定义一个全局的ThreadLocal,可以保证一个SqlSession对应一个线程
    private static ThreadLocal<SqlSession> local = new ThreadLocal<>();

    //通过一个公有的方法为外部提供会话的对象 >> 确保同一个线程操作的是同一个连接对象
    public static SqlSession openSession(){

        //我们用local去获取会话
        SqlSession sqlSession = local.get();
        //如果当前没有开启的会话就去创建一个,如果get到了就用这个[确保我们操作的是同一个连接对象]
        if(sqlSession == null){

            sqlSession = sqlSessionFactory.openSession();
            //将SqlSession对象绑定到当前线程上
            local.set(sqlSession);
        }
        return sqlSession;
    }

    /**
     * 关闭SqlSession对象并从当前线程中解绑
     * @param sqlSession 会话对象
     */
    public static void close(SqlSession sqlSession){

        if(sqlSession != null){

            sqlSession.close();
            local.remove();
        }
    }
}

🌔3、对于传递的参数为单个简单类型时,我们列举了几个案例

  • 根据 id、name、birth、sex 查询学生信息
  • 接口如下:
public interface StudentMapper {

    /**
     * 接口中的参数为单个简单类型时
     * 我们根据id、name、birth、sex查询
     */
    List<Student> selectById(Long id);
    List<Student> selectByName(String name);
    List<Student> selectByBrith(Date brith);
    List<Student> selectBySex(Character sex);
}
  • Mapper映射文件如下:
<?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="selectById" resultType="Student">
        select * from t_student where id = #{

     id}
    </select>
    <!--使用了类型内置别名-->
    <select id="selectByName" resultType="Student" parameterType="string">
        select * from t_student where name = #{

     name}
    </select>
    <select id="selectByBrith" resultType="Student">
        select * from t_student where birth = #{

     birth}
    </select>

    <select id="selectBySex" resultType="Student">
        select * from t_student where sex = #{

     sex}
    </select>
</mapper>
  • 测试程序如下:
public class StudentMapperTest {

    @Test
    public void testSelectById(){

        SqlSession sqlSession = SqlSessionUtil.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        // 根据id查的数据只能有一条,所以不应该用List集合来接收查询结果
        List<Student> students = mapper.selectById(1L);
        students.stream().forEach(student -> System.out.println(student));
        sqlSession.close();
    }
    @Test
    public void testSelectByName(){

        SqlSession sqlSession = SqlSessionUtil.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> students = mapper.selectByName("张三");
        students.stream().forEach(student -> System.out.println(student));
        sqlSession.close();
    }
    @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("2022-11-01");
        List<Student> students = mapper.selectByBrith(birth);
        students.stream().forEach(student -> System.out.println(student));
        sqlSession.close();
    }
    @Test
    public void testSelectBySex() throws ParseException {

        SqlSession sqlSession = SqlSessionUtil.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> students = mapper.selectBySex('女');
        students.stream().forEach(student -> System.out.println(student));
        sqlSession.close();
    }
}
  • 测试结果 >> 成功
  • 对于SQL语句可以指定 parameterType 的,如果不指定那么将有mybatis底层自动识别
  • 而且mybatis还内置了一些基础类的别名:

&nbsp;
&nbsp;


二、Map参数

1、 Map参数是什么意思?;

  • 就是我们要在数据库表接口中的操作方法传递的参数 >> 是一个 Map 集合
  • 一般用于插入数据时候封装对象,集合的key就是传递参数占位符里面的内容

2、 通过一个案例来说明如何使用?【只给出接口中的方法、mapper中的SQL语句、测试片段其余部分与上述案例相同】;

(1)接口中的方法

/**
    * 通过map参数保存学生信息,单个参数非简单类型
    * @param map map对象
    * @return 影响数据条数
*/
int insertStudentByMap(Map<String, Object> map);

(2)mapper 中的 SQL 语句

<insert id="insertStudentByMap">
    <!--占位符中传递的是map的key-->
    insert into t_student (id, name, age, sex, birth, height)
    values (null, #{

     name}, #{

     age}, #{

     sex}, #{

     birth}, #{

     height})
</insert>

(3)测试片段

    @Test
    public void testInsertStudentByMap(){

        SqlSession sqlSession = SqlSessionUtil.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        Map<String, Object> map = new HashMap<>();
        // 一个map对象代表一个学生信息, map 的key对应表中字段--value对应属性值
        map.put("name", "李元霸");
        map.put("age", 20);
        map.put("height", 1.81);
        map.put("sex", '男');
        map.put("birth", new Date());

        int count = mapper.insertStudentByMap(map);

        sqlSession.commit();
        sqlSession.close();
    }

(4)运行结果如下:
&nbsp;

三、实体类参数

1、 这是我们比较常用的方式,用一个普通java类来封装我们的数据库表中的字段;

2、 我们现在要通过实体类参数插入一条数据;
(1)创建Student类

package com.powernode.mybatis.pojo;

import java.util.Date;

/**
 * @author Bonbons
 * @version 1.0
 */
public class Student {

    private Long id;
    private String name;
    private Integer age;
    private Double height;
    private Date birth;
    private Character sex;

    @Override
    public String toString() {

        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                ", brith=" + 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 brith) {

        this.birth = birth;
    }

    public Character getSex() {

        return sex;
    }

    public void setSex(Character sex) {

        this.sex = sex;
    }

    public Student() {

    }

    public Student(Long id, String name, Integer age, Double height, Date brith, Character sex) {

        this.id = id;
        this.name = name;
        this.age = age;
        this.height = height;
        this.birth = brith;
        this.sex = sex;
    }
}

(2)接口中的方法

/**
* 通过POJO类对象传递参数信息
* @param student 学生类的对象
* @return 影响数据条数
*/
int insertStudentByPOJO(Student student);

(3)映射文件中的 SQL 语句

  • 此处占位符内的字段是获取对应属性值的 get方法去掉get和将首字母转化为小写后的参数
<insert id="insertStudentByPOJO" parameterType="student">
        insert into t_student (id, name, age, sex, birth, height)
        values (null, #{

     name}, #{

     age}, #{

     sex}, #{

     birth}, #{

     height})
</insert>

(4)相应的测试片段

    @Test
    public void testInsertStudentByPOJO(){

        SqlSession sqlSession = SqlSessionUtil.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        Student student = new Student(null, "李白", 30, 1.82, new Date(), '女');

        int count = mapper.insertStudentByPOJO(student);
        System.out.println(count);
        sqlSession.commit();
        sqlSession.close();
    }

(5)测试结果如下
&nbsp;


四、多参数

🌔 1、以上的案例都是参数只有一个时,那么如果我们的方法需要传递多个参数应该如何处理呢?

  • mybatis 为我们提供了两种默认的参数传递机制
  • 假如传递的为两个参数,此处以根据姓名性别查询学生数据
  • 那么在接口中的方法应该是这样的:
/**
* 根据名字和性别查询学生信息
* @param name 名字
* @param sex 性别
* @return 返回查询结果
*/
List<Student> selectByNameAndSex(String name, Character sex);
  • 重点来了,在Mapper的映射文件的SQL语句中,我们应该怎么写呢?【占位符中应该填什么参数】
<select id="selectByNameAndSex" resultType="student">
    select * from t_student where name = #{

     } and sex = #{

     }
</select>

🌔2、mybatis为我们提供了两种默认的参数?

  • 第一种:使用参数 argNN对应我们第 i - 1 个参数】
  • 第二种:使用参数paramNN对应我们的第i个参数】

所以上面的SQL语句可以写成一下两种形式:【此处是为了方便看将两条ID相同的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>
  • 在测试文件中,我们正常调用即可
public void testSelectByNameAndSex(){

    SqlSession sqlSession = SqlSessionUtil.openSession();
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    List<Student> students = mapper.selectByNameAndSex("李白", '女');
    students.stream().forEach(student -> System.out.println(student));
    sqlSession.commit();
    sqlSession.close();
}

🌔3、我们还可以采用 @Param 注解的方式指定使用什么参数名

  • 在我们制定接口方法的时候,我们可以通过 @Param 注解指明使用什么参数名 【可以参考下面的方法】
/**
* 通过注解来为多个参数指明参数名,底层实现不再使用默认的arg、param了
* map.put("name", name)
* @param name
* @param sex
* @return
*/
List<Student> selectByNameAndSex2(@Param("name") String name, @Param("sex") Character sex);
  • 就是在参数类型前面添加 @Param(参数名)
  • 在我们写SQL语句的时候就可以使用我们制定的参数名了
<select id="selectByNameAndSex2" resultType="student">
    select * from t_student where name = #{

     name} and sex = #{

     sex}
</select>
  • 此时仍然可以使用 param1、param2 … 作为参数名传递参数,但是不能使用 arg0、arg1、… 的方式了
  • 测试方法中的代码块不变:
public void testSelectByNameAndSex2(){

    SqlSession sqlSession = SqlSessionUtil.openSession();
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    List<Student> students = mapper.selectByNameAndSex2("李白", '女');
    students.stream().forEach(student -> System.out.println(student));
    sqlSession.commit();
    sqlSession.close();
}

🌔4、可以根据一下内容简单了解一下Param注解的原理:

&nbsp;
&nbsp;