输入参数映射和输出结果映射

mapper.xml映射文件中定义了操作数据库的SQL语句,每个SQL是一个statement,映射文件是MyBatis的核心。

1、传入参数到sql语句中的处理

parameterType输入参数映射:指定要传递什么类型的参数给SQL语句,之后从输入对象中 取值 设置 在SQL语句中。(输入参数的类型)

模块名:mybatis-006-param

表:t_student

表中现有数据:

pojo类:

Student.java

package com.powernode.mybatis.pojo;

import java.util.Date;

/**
 * 学生类
 */
public class Student {
    private Long id;
    private String name;
    private Integer age;
    private Double height;
    private Character sex;
    private Date birth;
    // constructor
    // setter and getter
    // toString
}

1.1 传入一个简单类型的参数

  • 当Mapper接口中方法的参数只有一个,且传入一个简单类型的参数到SQL语句中时

  • 结论:#{} 里面随便写内容就可以传值。对于 ${} 来说,注意加单引号。

  • 简单类型有哪些:

    • byte short int long float double char(Java的几本数据类型)

    • Byte Short Integer Long Float Double Character(包装类)

    • String

    • java.util.Date

    • java.sql.Date

需求:根据name查、根据id查、根据birth查、根据sex查

Mapper接口:

StudentMapper.java

package org.example.mapper;

import org.example.pojo.Student;

import java.util.List;

public interface StudentMapper {
    /**
     * 当接口中的方法的参数只有一个,且参数的数据类型都是简单类型
     * 根据id查询,根据name查询,根据birth查询,根据sex查询
     */
    List<Student> selectById(Long id);
    List<Student> selectByName(String name);
    List<Student> selectByBirth(String birth);
    List<Student> selectBySex(Character sex);
}

Mapper映射文件:

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="org.example.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="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>

测试:

StudentMapperTest

    
package org.example.test;

import org.apache.ibatis.session.SqlSession;
import org.example.mapper.StudentMapper;
import org.example.pojo.Student;
import org.example.utils.SqlSessionUtil;
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(1L);
        students.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.forEach(student -> System.out.println(student));
        sqlSession.close();
    }

    @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();
    }
    
        @Test
    public void testSelectByBirth(){
        try {
            Date birth = new SimpleDateFormat("yyyy-MM-dd").parse("2022-08-16");
            List<Student> students = mapper.selectByBirth(birth);
            students.forEach(student -> System.out.println(student));
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
	}
}

  • 其中sql语句中的#{}中的javaType,jdbcType,以及select标签中的parameterType属性,都是用来帮助mybatis确定传过来的参数是什么类型的。不过这些配置多数是可以省略的。因为mybatis它有强大的自动类型推断机制。

    • javaType:可以省略

    • jdbcType:可以省略

    • parameterType:可以省略

1.2 实体类或自定义类型

传入单个pojo对象或自定义类型对象给SQL映射文件 。

处理:在#{} 中填入java对象的属性名(成员变量名),取出其属性值设置给SQL语句。这个属性名其本质上是:set/get方法名去掉set/get之后的名字。

需求:插入一条Student数据

StudentMapper接口:

/**
 * 保存学生数据
 * @param student
 * @return
 */
int insert(Student student);

StudentMapper.xml: 

<insert id="insert">
  insert into t_student values(null,#{name},#{age},#{height},#{birth},#{sex})
</insert>

StudentMapperTest.testInsert: 



@Test
public void testInsert(){
    Student student = new Student();
    student.setName("李四");
    student.setAge(30);
    student.setHeight(1.70);
    student.setSex('男');
    student.setBirth(new Date());
    int count = mapper.insert(student);
    SqlSessionUtil.openSession().commit();
}

运行正常,数据库中成功添加一条数据。

  • 其中sql语句中的#{}中的javaType,jdbcType,以及select标签中的parameterType属性,都是用来帮助mybatis进行传过来的参数的类型确定的。不过这些配置多数是可以省略的。因为mybatis它有强大的自动类型推断机制。

    • javaType:可以省略

    • jdbcType:可以省略

    • parameterType:可以省略

1.3 Map类型

 如果一条数据是用Map集合封装的。

处理:在#{}中用map集合的key取出对应的value设置给SQL语句。

需求:根据name和age查询

StudentMapper接口


/**
* 根据name和age查询
* @param paramMap
* @return
*/
List<Student> selectByParamMap(Map<String,Object> paramMap);
StudentMapperTest.testSelectByParamMap


@Test
public void testSelectByParamMap(){
    // 准备Map
    Map<String,Object> paramMap = new HashMap<>();
    paramMap.put("nameKey", "张三");
    paramMap.put("ageKey", 20);

    List<Student> students = mapper.selectByParamMap(paramMap);
    students.forEach(student -> System.out.println(student));
}
StudentMapper.xml


<select id="selectByParamMap" resultType="student">
  select * from t_student where name = #{nameKey} and age = #{ageKey}
</select>

测试运行正常。

  • 其中sql语句中的#{}中的javaType,jdbcType,以及select标签中的parameterType属性,都是用来帮助mybatis进行传过来的参数的类型确定的。不过这些配置多数是可以省略的。因为mybatis它有强大的自动类型推断机制。

    • javaType:可以省略

    • jdbcType:可以省略

    • parameterType:可以省略

1.4 传入多个参数

MyBatis中允许有多个输入参数,可以让Mapper接口中的方法传多个输入参数过去给sql语句。

本质上是使用Map集合来封装数据,这个Map集合是MyBatis自动创建的。

1.4.1 不使用@Param注解

  • 实现原理:mybatis底层会自动创建一个Map集合来存储这些参数,这个Map集合以arg0/param1作为key以方法上的参数作为value存储在这个Map集合中

  • 取值的时候用这个Map集合的key就可以取出对应的value

  • mybatis部分源码
    
    
    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查询

StudentMapper接口


    /**
     * 根据name和sex查询
     * @param name
     * @param sex
     * @return
     */
    List<Student> selectByNameAndSex(String name, Character sex);
StudentMapperTest.testSelectByNameAndSex


@Test
public void testSelectByNameAndSex(){
    List<Student> students = mapper.selectByNameAndSex("张三", '女');
    students.forEach(student -> System.out.println(student));
}
StudentMapper.xml


<select id="selectByNameAndSex" resultType="student">
  select * from t_student where name = #{name} and sex = #{sex}
</select>

执行结果:

异常信息描述了:name参数找不到,可用的参数包括[arg1, arg0, param1, param2]

修改StudentMapper.xml配置文件:尝试使用[arg1, arg0, param1, param2]取参数

StudentMapper.xml


<select id="selectByNameAndSex" resultType="student">
  <!--select * from t_student where name = #{name} and sex = #{sex}-->
  select * from t_student where name = #{arg0} and sex = #{arg1}
</select>

运行结果:

再次尝试修改StudentMapper.xml文件

StudentMapper.xml


<select id="selectByNameAndSex" resultType="student">
  <!--select * from t_student where name = #{name} and sex = #{sex}-->
  <!--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>

通过测试可以看到:

  • arg0 是第一个参数

  • param1是第一个参数

  • arg1 是第二个参数

  • param2是第二个参数

注意:使用mybatis3.4.2之前的版本时:要用#{0}和#{1}这种形式。

1.4.2 使用@Param注解

使用@Param注解给要传入的多个参数命名。

  • 实现原理:mybatis底层会自动创建一个Map集合来存储这些参数,这个Map集合以@Param注解的value属性值为Map的key以方法上的参数作为value存储在这个Map集合中。

  • 取值的时候用这个Map集合的key就可以取出对应的value

在映射文件中通过key获取对应的value,并且parameterType可以不指定类型。

  • 注意:使用@Param()注解之后,arg0、arg1系列失效了,但param1和param2还可以用

需求:根据name和age查询

StudentMapper接口


    /**
     * 根据name和age查询
     * @param name
     * @param age
     * @return
     */
    List<Student> selectByNameAndAge(@Param(value="name") String name, @Param("age") int age);
	List<Student> selectByNameAndSex(@Param("name") String name,@Param("sex") Character sex);
StudentMapper.xml


<select id="selectByNameAndAge" resultType="Student">
  select * from t_student where name = #{name} and age = #{age}
</select>
StudentMapperTest.java


    @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();
    }

通过测试,一切正常。

2、resultType输出参数映射

resultType:指定将SQL语句的查询结果集的一条记录  映射成  指定类型的Java对象,并返回。(输出结果的类型)

模块名:mybatis-007-select

打包方式:jar

引入依赖:mysql驱动依赖、mybatis依赖、logback依赖、junit依赖。

引入配置文件:jdbc.properties、mybatis-config.xml、logback.xml

创建pojo类:Car

创建Mapper接口:CarMapper

创建Mapper接口对应的SQL映射文件:com/powernode/mybatis/mapper/CarMapper.xml

创建单元测试:CarMapperTest

拷贝工具类:SqlSessionUtil

2.1 返回简单类型

如果查询结果集只有一条数据并且是单个字段,那么resultType指定为简单类型,例如:根据id查询姓名,查询员工的总数量。

mapper接口:

public interface PersonMapper {
    /**
     * 根据id查询姓名
     */
    public String selectById(Integer id);

    /**
     * 查询人员的总数量
     */
    public Integer selectCount();
}

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="org.example.mapper.PersonMapper">

    <!--简单类型-->
    <!--public String selectById(Integer id);-->
    <select id="selectById" parameterType="int" resultType="string">
        SELECT person_name FROM person WHERE id = #{id}
    </select>

    <!--    public Integer selectCount();  -->
    <select id="selectCount" resultType="int">
        SELECT count(1) FROM person
    </select>

</mapper>

测试:

public class ResultTypeTest {

    /**
     * 测试resultType输出参数是简单类型的
     */
    @Test
    public void testSimpleParam(){
        SqlSession sqlSession = MybatisUtil.getSession();
        //获取Mapper接口的代理实现类对象
        PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);
        String name = personMapper.selectById(3);
        System.out.println(name);

        Integer count = personMapper.selectCount();
        System.out.println("总数=" + count);
        sqlSession.close();
    }
}

2.2 返回一个pojo类对象

当查询的结果,有对应的实体类,并且查询结果只有一条时,resultType指定为:pojo对象的类型。

  • 查询结果集的字段名和pojo类对象的属性名要一致,这样查询结果集中的结果才能赋值给pojo对象的属性(成员变量)

CarMapper.java


package com.powernode.mybatis.mapper;

import com.powernode.mybatis.pojo.Car;


public interface CarMapper {

    /**
     * 通过id主键进行查询:结果最多只有一条
     * @param id
     * @return
     */
    Car selectById(Long id);
}
CarMapper.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.CarMapper">
    <select id="selectById" resultType="Car">
        select
            id,
            car_num as carNum,
            brand,
            guide_price as guidePrice,
            produce_time as produceTime,
            car_type as carType
        from t_car
        where id = #{id}
    </select>
    </select>
</mapper>
CarMapperTest.java


package com.powernode.mybatis.test;

import com.powernode.mybatis.mapper.CarMapper;
import com.powernode.mybatis.pojo.Car;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.junit.Test;

public class CarMapperTest {

    @Test
    public void testSelectById(){
        CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
        Car car = mapper.selectById(35L);
        System.out.println(car);
        sqlSession.close();
    }
}

执行结果:

2.3 返回List<T>集合

  • 如果查询记录是多条时,则使用实体类的集合来接收,将返回的多条记录用集合来存储,resultType指定为:集合中存储的元素的类型。

  • 如果使用单个实体类接收会出现异常,TooManyResultsException异常:你期望的结果是返回一条记录,但实际的SQL语句在执行的时候,返回的记录条数是多条。

CarMapper.java


/**
* 查询所有的Car
* @return
*/
List<Car> selectAll();
CarMapper.xml


<select id="selectAll" resultType="Car">
  select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car
</select>
CarMapperTest.testSelectAll


@Test
public void testSelectAll(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    List<Car> cars = mapper.selectAll();
    cars.forEach(car -> System.out.println(car));
}

2.4 返回一个Map集合

  • 如果查询结果集和实体类的属性不一致时,可以使用Map集合来接收,resultType指定为:Map集合,比如:查询员工姓名,薪资,部门名称(两张表的查询),每条记录的字段名为Map集合的key,字段值为Map集合的value。
  • 查询结果如果只有一条数据,则返回一个Map集合即可。

CarMapper.java


/**
 * 通过id查询一条记录,将记录放到Map集合
 * @param id
 * @return
 */
Map<String, Object> selectByIdRetMap(Long id);
CarMapper.xml


<select id="selectByIdRetMap" resultType="map">
  select id,
    car_num as carNum,
    brand,
    guide_price as guidePrice,
    produce_time as produceTime,
    car_type as carType 
   from t_car 
   where id = #{id}
</select>
CarMapperTest.java


@Test
public void testSelectByIdRetMap(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    Map<String,Object> car = mapper.selectByIdRetMap(35L);
    System.out.println(car);
}

执行结果:

2.5 返回List<Map>

  • 如果返回的不是一条记录,是多条记录,只采用一个Map集合接收,这样会出现之前的异常:TooManyResultsException

  • 查询结果集有多条记录时,则需要返回一个存储Map集合的List集合。List<Map>等同于List<Car>

  • resultType属性指定为:Map类型

CarMapper接口


/**
     * 查询所有的Car,返回一个List集合。List集合中存储的是Map集合。
     * @return
     */
List<Map<String,Object>> selectAllRetListMap();
CarMapper.xml


<select id="selectAllRetListMap" resultType="map">
  select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car
</select>
CarMapperTest.java

@Test
public void testSelectAllRetListMap(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    List<Map<String,Object>> cars = mapper.selectAllRetListMap();
    System.out.println(cars);
}

执行结果:

2.5 返回Map<String,Map>

  • 选择小Map集合的一个key作为大Map集合的key。用Car的id做key,以后取出对应的Map集合时更方便。

  • 通过在Mapper接口的方法上加@MapKey("id")注解,指定大Map集合的key为小Map集合的哪个key

  • resultType属性指定为:Map类型。

CarMapper接口


/**
     * 获取所有的Car,返回一个Map集合。
     * Map集合的key是Car的id。
     * Map集合的value是对应Car。
     * @return
     */
@MapKey("id")
Map<Long,Map<String,Object>> selectAllRetMap();
CarMapper.xml


<select id="selectAllRetMap" resultType="map">
  select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car
</select>
CarMapperTest.testSelectAllRetMap


@Test
public void testSelectAllRetMap(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    Map<Long,Map<String,Object>> cars = mapper.selectAllRetMap();
    System.out.println(cars);
}

执行结果:

{
64={carType=燃油车, carNum=133, guidePrice=50.30, produceTime=2020-01-10, id=64, brand=丰田霸道}, 
66={carType=燃油车, carNum=133, guidePrice=50.30, produceTime=2020-01-10, id=66, brand=丰田霸道}, 
67={carType=燃油车, carNum=133, guidePrice=50.30, produceTime=2020-01-10, id=67, brand=丰田霸道}, 
69={carType=燃油车, carNum=133, guidePrice=50.30, produceTime=2020-01-10, id=69, brand=丰田霸道},
......
}

2.6 resultMap手动结果映射

首先来看看Mybatis在实现resultType自动结果集映射的大概原理:

结果映射?:查询结果集的列映射成(赋值给)java对象的属性。

  • resultType属性:可以将查询结果集映射为指定的实体类,

    • 注意:但需要实体类的属性名和SQL查询结果的列名一样,才能映射到实体类中。

如果结果集的列名和实体类的字段名不一致,那么会赋值失败,成功进行结果映射的有三种方法:

  • 第一种方式:在SQL语句中使用 as关键字 给列起别名(通过SQL解决)

    • 实现结果集的列名和实体类的属性名一致

  • 第二种方式:在SQL映射文件中使用resultMap标签进行结果映射,这个标签就在mapper根标签的下一级(手动映射)

  • 第三种方式:在mybatis核心配置文件中开启驼峰命名自动映射(配置settings)

    • 遵循命名规范,再开启驼峰命名自动映射,就可以实现映射

2.6.1 使用resultMap标签进行结果映射

在映射文件中,使用resultMap标签来定义一个结果集映射,手动进行结果映射。 

应用:

  • resultMap手动结果集映射可以实现将查询结果映射为复合型的实体类,比如在查询结果映射对象中包括实体类或List集合作为属性,实现一对一查询或一对多查询。 否则用resultType的话需要创建一个vo类,因为实体类属性和结果集不对应。
CarMapper接口


package org.example.mapper;

import org.example.pojo.Car;

import java.util.List;

public interface CarMapper {
    /**
     * 查询所有的Car信息,使用resultMap标签进行结果映射
     * @return
     */
    List<Car> selectAllByResultMap();
}
CarMapper.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="org.example.mapper.CarMapper">

    <!--
        用resultMap标签:定义一个resultMap结果映射,在这个标签中:通过一系列的标签,指定数据库表的字段 如何映射成 java类的属性
        	id属性:resultMap的唯一标识,这个唯一标识将来在select标签中的resultMap属性中使用
        	type属性:查询结果集要映射成的java类(全限定类名),可以用类的别名
    -->
    <resultMap id="carResultMap" type="Car">
        <!--   id单标签用来配置主键的映射,其余用result单标签来配置映射。官方解释是:为了提高mybatis的性能。建议写上。-->
        <!--   property属性:pojo类的属性名;column属性:数据库表的字段名-->
        <id property="id" column="id"/>
        <result property="carNum" column="car_num"/>
        <!--  如果数据库表中字段名和java类的属性名是一样的话,则可以省略此配置-->
        <!-- <result property="brand" column="brand"></result>-->
        <result property="guidePrice" column="guide_price" />
        <result property="produceTime" column="produce_time" />
        <result property="carType" column="car_type" />
    </resultMap>

<!--    select标签中通过resultMap属性来指定你要使用的结果映射是哪个(通过resultMap的id来指定)-->
    <select id="selectAllByResultMap" resultMap="carResultMap">
        select * from t_Car
    </select>
</mapper>
CarMapperTest.java


package org.example;

import org.apache.ibatis.session.SqlSession;
import org.example.mapper.CarMapper;
import org.example.pojo.Car;
import org.example.utils.SqlSessionUtil;
import org.junit.Test;

import java.util.List;

public class TestCarMapper {
    @Test
    public void testselectAllByResultMap(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        List<Car> cars = mapper.selectAllByResultMap();
        cars.forEach(car -> System.out.println(car));
        sqlSession.close();
    }
}

2.7 返回总记录条数

CarMapper接口


/**
     * 获取总记录条数
     * @return
     */
Long selectTotal();
CarMapper.xml


<!--long是别名,可参考mybatis开发手册。-->
<select id="selectTotal" resultType="long">
  select count(*) from t_car
</select>
CarMapperTest.java


@Test
public void testSelectTotal(){
    CarMapper carMapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    Long total = carMapper.selectTotal();
    System.out.println(total);
}

  • 14
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值