Mybatis的增删改查和resultMap的使用

MyBatis的增删改查

总结:
测试增删改注意的两个重点:

  • 1.mybatis允许增删改直接定义一下返回值类型
    • Integer,Long,Boolean,void
  • 2.我们需要手动提交增删改的数据(查找的数据不用手动提交)
    • SqlSession sqlSession = sqlSessionFactory.openSession(true);//自动提交
      -
    • SqlSession sqlSession = sqlSessionFactory.openSession();//手动提交
    • sqlSession.commit();//手动提交

第一步:导入环境依赖,数据库的对应的实体类自己编写:
(这里也可以导入:mybatis代替mybatis-spring-boot-starter)

<!--mybatis-->
<dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
</dependency>
<dependencies>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

数据库:
在这里插入图片描述
实体类User:

package com.fan.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.ibatis.type.Alias;

import java.util.Date;
@Alias("User")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer id;
    private String userName;//驼峰命名的属性
    private String addr;
    private Integer age;
    private Date birthday;

}

第二步:创建持久层的接口mapper,编写增删改查的方法:
文件路径夹: com.fan.mapper

package com.fan.mapper;

import com.fan.domain.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

public interface UserMapper {
	//查找的方法
    public User getUserById(Integer id);//接口提供一个规范
	//增加的方法
    public void addUser(User user);
	//更新的方法
    public void updateUser(User user);
	//删除的方法
    public void deleteUserById(Integer id);

    @Select("select count(*) from user")
    public Integer getCount();
}

第三步:在Resources类路径下编写全局核心文件mybatis-config.xml文件:

注意,数据源的标签environments 和mapper标签最基本需要的;其他按需自己增加
mybatis-config.xml(将sql映射文件绑定注册到全局配置文件中):

<?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>

    <!--标签顺序:The content of element type "configuration" must match "
    (properties?,settings?,typeAliases?,typeHandlers?,
    objectFactory?,objectWrapperFactory?,reflectorFactory?,
    plugins?,environments?,databaseIdProvider?,mappers?)".-->
    <!--外部属性配置文件-->
    <properties resource="db.properties"></properties>
    <!--设置项settings-->
    <settings>
        <!--开启驼峰命名-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    <!--返回值的别名处理器-->
    <typeAliases>
        <!--批量处理实体类的别名-->
        <package name="com.fan.domain"/>
        <!--单独的为每个类,起别名,默认是类名小写,也可以头通过alias显式的指定别名是什么-->
        <!--<typeAlias type="com.fan.domain.User" alias="user"></typeAlias>-->
    </typeAliases>

    <environments default="mysql">
        <!--测试的数据源-->
        <environment id="mysql">
            <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>
    <databaseIdProvider type="DB_VENDOR"><!--DB_VENDOR数据库的供应商-->
        <!--为不同的数据库供应商起别名-->
        <property name="Mysql" value="mysql"/>
        <property name="Oracle" value="oracle"/>
        <property name="SQL Server" value="sqlserver"/>
    </databaseIdProvider>
    <!--sql映射文件的位置,将sql映射文件绑定到核心配置文件中-->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"></mapper><!--和resources文件夹下的sql映射文件绑定-->

        <!--和com.fan.mapper文件夹下的xxxmapper接口进行绑定,
        注意当我们使用mybatis-springboot-starter的时候,能自动关联mapper接口-->
        <!--<mapper class="com.fan.mapper.UserMapper"></mapper>-->
        <!--<package name="com.fan.mapper"/>-->
    </mappers>
</configuration>

第四步:在Resources文件夹下的mapper文件夹下编写sql映射文件:
UserMapper.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">

<!--
namespace:名称空间,有接口后要写接口的全路径名
id="selectUser":此sql语句的唯一标识,有接口后写接口中关联sql语句的接口方法的方法名
resultType="com.fan.pojo.User":此sql查询后对应的结果集对象的类,全路径名
#{id}:从传递的参数中取出id值
-->
<mapper namespace="com.fan.mapper.UserMapper">
    <insert id="addUser" parameterType="user">
        insert into user
        values (#{id},#{userName},#{addr},#{age},#{birthday})
    </insert>
    <update id="updateUser">
        update user
        set user_name=#{userName},
        addr=#{addr},
        age=#{age},birthday=#{birthday}
        where id=#{id}
    </update>
    <delete id="deleteUserById">
        delete from user where id=#{id}
    </delete>
    <!--User getUserById(Integer id)-->
    <select id="getUserById" resultType="User" >
      select * from user where id = #{id}
  </select>

</mapper>

第五步:编写测试类进行曾删改查的测试:
MapperMybatisTest :

import com.fan.domain.User;
import com.fan.mapper.UserMapper;
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 org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;

public class MapperMybatisTest {

    private SqlSessionFactory getsqlSessionFactory() throws IOException {
        //1.加载mybatis核心配置文件创建sqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        return sqlSessionFactory;
    }
    @Test//这里我使用的是junit5的jupiter单元测试
    public void test01() throws IOException {
        //1.加载mybatis核心配置文件创建sqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //2.sqlSessionFactory创建一个sqlSession会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //3.获取接口的实现类对象,此时的mapper相当于dao
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        System.out.println("打印mapper实例的类型:"+mapper.getClass());//打印mapper实例的类型:class com.sun.proxy.$Proxy10
        User user = mapper.getUserById(1);
        System.out.println(user);
    }

    @Test//这里我使用的是junit5的jupiter单元测试
    public void test02() throws IOException {
        SqlSessionFactory sqlSessionFactory = getsqlSessionFactory();
        //2.sqlSessionFactory创建一个sqlSession会话
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //3.获取接口的实现类对象,此时的mapper相当于dao
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        System.out.println("打印mapper实例的类型:"+mapper.getClass());//打印mapper实例的类型:class com.sun.proxy.$Proxy10
        Integer count = mapper.getCount();
        System.out.println("user数据库中的记录数:"+count);
    }
    //测试增删改查方法:
    @Test
    void testAdd() throws IOException {
        //获取sqlSeeesionFactory工厂
        SqlSessionFactory sqlSessionFactory = getsqlSessionFactory();
        //获取与数据库的一次sql会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //获取相当于dao层的实现类
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.addUser(new User(null,"刺激战场","蓝洞",5,new Date()));
        //必须提交事务,否则数据库不能写入提交数据
        sqlSession.commit();
       //关闭此次sql会话
        sqlSession.close();
    }
    @Test
    void testUpdateUser() throws IOException {
        SqlSessionFactory sqlSessionFactory = getsqlSessionFactory();
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.updateUser(new User(6,"刺激战场","蓝洞",5,new Date()));
        sqlSession.commit();
        sqlSession.close();
    }
    @Test
    void testDeleteUser() throws IOException {
        //获取核心对象SqlSessionFactory对象
        String sources = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(sources);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取和数据库的一次sql会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.deleteUserById(11);
        //将这次会话提交后关闭
        sqlSession.commit();
        sqlSession.close();
    }

}

测试增删改注意的两个重点:
增删改的接口的方法返回值可以是void,Integer,Long,Boolean.

在这里插入图片描述

jdbcType的使用和作用:

 <!--resultMap自定义结果映射规则-->
 <resultMap id="BaseresultMap" type="com.example.entity.Book">
     <id column="id" property="id" jdbcType="INTEGER"></id>
     <result column="book_name" property="bookName" jdbcType="VARCHAR"></result>
     <result column="book_author" property="bookAuthor" jdbcType="VARCHAR"></result>
 </resultMap>
####或者这种方式
<insert id="saveRole">
    insert into role values (
        #{roleId},
        #{name},
        #{remarks},
        #{orderNo},
        #{createBy,jdbcType=VARCHAR},
        #{createDept,jdbcType=VARCHAR},
        #{createTime,jdbcType=DATE},
        #{updateBy,jdbcType=VARCHAR},
        #{updateTime,jdbcType=DATE}
    )
</insert>

这样,保证了前四种是不能为空的前提下,而后面几项为空时也不至于程序报错。如果createBy为空,插入的时候mybatis不知道具体转换成什么jdbcType类型,通常会使用一个默认设置,虽然默认配置一般情况下不会出错,但是遇到个别情况还是会有问题的。Mybatis经常出现的:无效的列类型: 1111 错误,就是因为没有设置JdbcType造成的。

增加jdbcType这是为了程序的安全性,使一些特殊情况,当传入的参数为name为空时不会使程序出现问题,当name为空时,mybatis不知道具体要转换成什么jdbcType类型,有些特殊情况会报错,Mybatis经常出现的:无效的列类型: 1111 错误,就是因为没有设置JdbcType造成的。在Mybatis中,也明文建议在映射字段数据时需要将JdbcType属性加上。这样相对来说是比较安全的。

常见的类型对应关系如下:

JDBC Type           Java Type
CHAR                String
VARCHAR             String
LONGVARCHAR         String
NUMERIC             java.math.BigDecimal
DECIMAL             java.math.BigDecimal
BIT                 boolean
BOOLEAN             boolean
TINYINT             byte
SMALLINT            short
INTEGER             INTEGER
BIGINT              long
REAL                float
FLOAT               double
DOUBLE              double
BINARY              byte[]
VARBINARY           byte[]
LONGVARBINARY       byte[]
DATE                java.sql.Date
TIME                java.sql.Time
TIMESTAMP           java.sql.Timestamp
CLOB                Clob
BLOB                Blob
ARRAY               Array
DISTINCT            mapping of underlying type
STRUCT              Struct
REF                 Ref
DATALINK            java.net.URL

总结:加上jdbcType原因: 当传入字段值为null,时,需要加入. 否则报错.

获取自增主键的值:

原生的JDBC获取数据库自增主键的方式:

使用Statement中的GetGeneratedKeys()方法获取数据库生成的主键值:在这里插入图片描述

自增主键的作用和使用方法:

现在的获取数据库自增主键的方式:

一般用于insert标签上,也可以用在update标签上,其他标签不能写
当我们想数据库插入一条记录的时候,我们想在前端数据表格获取其id,一般就需要使用自增的主键

分两步:

  1. 第一步获取数据库的自增主键:useGeneratedKeys=“true”
  2. 第二步:封装自增主键到实体类的属性中:keyProperty=“id”

在这里插入图片描述
代码演示:

sql映射文件UserMapper.xml:

<insert id="addUser" parameterType="user" useGeneratedKeys="true" keyProperty="id">
        insert into user
        values (#{id},#{userName},#{addr},#{age},#{birthday})
    </insert>

测试类MapperMybatisTest:

  @Test
    void testAdd() throws IOException {
        //获取sqlSeeesionFactory工厂
        SqlSessionFactory sqlSessionFactory = getsqlSessionFactory();
        //获取与数据库的一次sql会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //获取相当于dao层的实现类
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = new User(null, "刺激战场", "蓝洞", 5, new Date());
        mapper.addUser(user);
        System.out.println("使用主键自增策略获取数据库生成的主键:"+user.getId());
        //必须提交事务,否则数据库不能写入提交数据
        sqlSession.commit();
       //关闭此次sql会话
        sqlSession.close();
    }

结果:

在这里插入图片描述

Oracle怎么获取自增主键的值:

before的使用方法:
在这里插入图片描述

after的使用方法:
在这里插入图片描述

before和after运行顺序:

在这里插入图片描述

当数据库为非自增的主键的时候,我们使用before,after使用有部分问题的;

MyBatis的接口方法的参数如何与映射文件进行关联:

接口方法中的参数可能有 如下几种。

  1. 单个参数
  2. 多个参数

在这里插入图片描述

1.单个参数:

使用单个参数,其中mapper接口方法如下:

public interface EmpMapper {
    //基本的增删改查方法,单个参数
    public Emp getEmpById(Integer id);
}

在sql映射文件中:

	<!--public Emp getEmpById(Integer id);-->
    <select id="getEmpById" resultType="com.fan.pojo.Emp" databaseId="mysql" >
        select * from emp where id = #{id}
    </select>

其中上面的 #{id} 中的 id,可以随便写,都不会对查询造成实质影响。

2.多个参数:

多个参数的时候:mybatis会做特殊处理,默认将参数会被封装成一个map,而这个map中默认的key是param1,param2…,而每一个key对应的value值是我们需要的参数值。

处理多参方法一:使用封装的map中的原生key名称:

当我们这样使用的时候会报错:
Cause: org.apache.ibatis.binding.BindingException: Parameter ‘1’ not found. Available parameters are [id, userName, param1, param2]
就是说我们的参数可以是这四个:id, userName, param1, param2
在这里插入图片描述
接口中的方法:

package com.fan.mapper;

import com.fan.domain.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

public interface UserMapper {
    //测试封装多个参数
    public User getUserByIdandName(
           Integer id,String userName);
         
}

sql映射文件中的代码:

<!--测试多个参数的封装-->
    <select id="getUserByIdandName" resultType="com.fan.domain.User">
        select * from user
        where id = #{param1} and user_name = #{param2}
    </select>

测试代码:

import com.fan.domain.User;
import com.fan.mapper.UserMapper;
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 org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.InputStream;

public class MapperParamsTest {

    private SqlSessionFactory getSqlSessionFactory() throws IOException {
        String resources = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resources);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        return sqlSessionFactory;
    }
    @Test
    void testMultyParamsTest() throws IOException {
        //获取mybatis的核心对象sqlSessionFactory
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        //获取和数据库的一次sql会话,参数true表示自动提交
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //获取接口的代理对象mapper
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        System.out.println("接口的代理对象:"+mapper);
        User user = mapper.getUserByIdandName(8, "和平精英");
        System.out.println("测试封装的参数是否完整:"+user);

    }
}

然后打印的结果;
测试封装的参数是否完整:User(id=8, userName=和平精英, addr=广州, age=3, birthday=Mon Apr 11 00:00:00 GMT+08:00 2022)

总结:
在sql映射文件中直接使用#{param1},#{param2}来取map中的参数值。
这种方法不推荐,对于书写和阅读都有障碍,当参数很多的时候,我们不容易区分

处理多参方法二:命名参数(给接口参数使用@Param注解起别名):

最好是使用命名参数(@Param(“ID”)为命名参数),指定封装map的key,实现很简单,在接口方法的参数声明处使用Param注解,指定值作为map的key.

在接口的方法参数中,参数前面明确使用一个注解@Param来指定封装参数时的map的key,然后sql映射文件中使用#{id},#{username}等来取map中的value值参数多的时候不推荐:
在这里插入图片描述

在这里插入图片描述

代码演示:
dao层接口方法UserMapper.java:

package com.fan.mapper;

import com.fan.domain.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

public interface UserMapper {
    //测试封装多个参数,@Param("ID")为命名参数
    public User getUserByIdandName(
            @Param("ID")Integer id,
            @Param("USERNAME")String userName);
}

与之对应的实现(sql映射文件.UserMapper.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">

<!--
namespace:名称空间,有接口后要写接口的全路径名
id="selectUser":此sql语句的唯一标识,有接口后写接口中关联sql语句的接口方法的方法名
resultType="com.fan.pojo.User":此sql查询后对应的结果集对象的类,全路径名
#{id}:从传递的参数中取出id值
-->
<mapper namespace="com.fan.mapper.UserMapper">

    <!--测试多个参数的封装-->
    <select id="getUserByIdandName" resultType="User">
        select * from user where id=#{ID} and user_name = #{USERNAME}
    </select>

</mapper>

测试类用上一个的,不变:

打印结果正常:测试封装的参数是否完整:User(id=8, userName=和平精英, addr=广州, age=3, birthday=Mon Apr 11 00:00:00 GMT+08:00 2022)

多参处理方式三:POJO,Map,TO:

总结接口方法传递参数的使用规则:

  1. 开发中和业务逻辑有关的多个参数我们使用pojo对象的参数
  2. 如果和业务逻辑无关,不经常使用,使用map参数;如果和业务逻辑无关,且经常使用,则使用自定义的TO对象

1、如果是业务参数模型数据,使用POJO,接口就变为一个参数(如Emp emp,将我们的多个参数放到一个emp中),sql中使用#{}来获取数据,#{}中使用属性名称即可获取POJO对应属性的值。

2、如果不是业务参数,但是参数很少,可以使用Param注解(上面已经提到)或者是map方式(该方式中#{}使用map的键即可获取对应键的值)。

3、如果是非业务参数比较多,就是用一个数据传输对象TO(Transfer Object)。

4、参数是Set集合,也是封装为map,其中key只能为collection。

5、参数是List集合,也是封装为map,其中key只能为collection或list。

6、参数是数组,也是封装为map,其中key只能为array。

在这里插入图片描述

测试pojo封装参数,接口参数是一个pojo 对象:

代码演示:
mapper接口中方法:

	//测试封装多个参数- --传输pojo对象
    public Emp findEmpByNameAndGender(Emp emp);

sql映射文件:

	<select id="findEmpByNameAndGender" resultType="com.fan.pojo.Emp">
        select * from emp
        where
            last_name = #{lastName}
            and gender = #{gender}
    </select>

测试,正常封装成功。

测试map封装参数:

如果多个参数不是业务模型中的数据,没有对应的pojo,为了方便,我们可以向接口方法传入一个map参数,
#{我们map中定义的key}:可以取出我们map中对应的key的值

在这里插入图片描述

代码演示:
mapper接口:

//测试map封装数据
    public User getUserByIdandName(Map<String, Object> map);

sql映射文件中:

<!--测试多个参数的封装-->
    <select id="getUserByIdandName" resultType="User">
        select * from user
        where id = #{id} and user_name = #{userName}
    </select>

测试类:

@Test
    void testMultyParamsTest() throws IOException {
        //获取mybatis的核心对象sqlSessionFactory
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        //获取和数据库的一次sql会话,参数true表示自动提交
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //获取接口的代理对象mapper
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        System.out.println("接口的代理对象:"+mapper);

        Map<String, Object> map = new HashMap<String, Object>();
        map.put("id",8);
        map.put("userName","和平精英");
        //方法传递参数:我们可以才方法传递散乱的参数之前,将所有的参数自行封装到一个map中
        //User user = mapper.getUserByIdandName(8, "和平精英");
        User user = mapper.getUserByIdandName(map);
        System.out.println("测试封装的参数是否完整:"+user);
    }

在这里插入图片描述

参数封装的扩展:

在这里插入图片描述

#{}和${}的区别:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

参数处理中的字段为null:

在这里插入图片描述

(此项设置主要针对oracle 数据库,Mysql数据库可以正常对应null)

在这里插入图片描述
oracle报错信息:
在这里插入图片描述

处理null字段的方式一:单个字段使用jdbcType=NULL

在这里插入图片描述

处理null字段的方式二:mybatis全局配置文件使用setting name=“jdbcTypeForNull” value="NULL"

在这里插入图片描述

select查询返回List集合

在这里插入图片描述

注意:resultType就是我们希望mybatis把我们的每一条记录封装成什么类型
所以我们不论返回的是一个list或者map,我们都写的是集合中元素的类型
在这里插入图片描述

在这里插入图片描述

测试:

在这里插入图片描述

select查询返回一个Map集合:

注意:resultType就是我们希望mybatis把我们的每一条记录封装成什么类型
所以我们不论返回的是一个list或者map,我们都写的是集合中元素的类型

@MapKey(“id”)//告诉mybatis封装这个map的时候使用哪个属性作为map的key,返回多条记录的时候不带此标签会报错

mapper接口的方法:

	//查询返回一个Map集合
    @MapKey("id")//告诉mybatis封装这个map的时候使用哪个属性作为map的key,不带此标签会报错
    public Map<String,Object> selectEmpByName2(Emp emp);

注意事项:

1.sql映射文件:返回值类型不建议使用map/java.util.Map,可能会封装出现问题,在@MapKey(“lastName”)使用的时候封装异常。

2.这里返回值类型建议写Map中的元素类型Emp(mybatis3接口方法可能会爆红,但是不影响正常运行),在@MapKey(“lastName”)使用的时候能正常显示。

	<!--public Map<String,Object> selectEmpByName2(Emp emp)-->
    <select id="selectEmpByName2" resultType="java.util.Map">
        select * from emp
        where last_name like #{lastName} and gender = #{gender}
    </select>

测试类:

@Test//测试返回值类型是一个Map
    public void testListAndMap2() throws IOException {
        //1.使用数据库的核心是一个sqlsessionfactory对象
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        //开启和sql的会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        Map<String, Object> map = mapper.selectEmpByName2(new Emp(null, "%r%", null, "0"));
        System.out.println("测试返回值是一个map集合:"+map.toString());
    }

测试打印map:
在这里插入图片描述

resultMap的用法:

resultType可以把查询结果封装到pojo类型中,但必须pojo类的属性名和查询到的数据库表的字段名一致
如果sql查询到的字段与pojo的属性名不一致,则需要使用resultMap将字段名和属性名对应起来,进行手动配置封装,将结果映射到pojo中;resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询

介绍三种处理我们javaBean中属性名和数据库字段/列名 不对应的情况:

第一种方式:在sql映射文件中使用select user_name userName来设置别名的方式查询,并将结果集封装到javabean中。

第二种方式:当数据库字段和javabean属性符合驼峰命名的规则的时候,我们可以在全局配置文件中setting标签中开启驼峰命名匹配。如数据库字段是user_name 而javabean中属性为userName;

第三种方式:当字段/属性不一致比较多,而且还经常使用,我们可以考虑使用自定义resultMap来处理不一致的字段,让其将数据库的查询结果也能成功封装到javabean中。

在这里插入图片描述

参数说明:resultMap最终还是要将结果映射到pojo上,type就是指定映射到哪一个pojo
id:定义主键 ,非常重要。如果是多个字段,则定义多个id
property:主键在pojo中的属性名
column:主键在数据库中的列名

普通查询:属性封装结果集(ResultMap):

代码演示:
mapper中的接口方法

 //测试resultMap的封装的
    public User findUserByResultMap(Integer id);

sql映射文件代码:

 <!--使用resultMap来处理数据库字段和javabean属性的不一致-->
 <!-- resultMap最终还是要将结果映射到pojo上,type就是指定映射到哪一个pojo -->
    <resultMap id="MyUser" type="com.fan.domain.User">
        <!--定义id的封装规则,id封装主键底层有优化-->
        <id column="id" property="id"></id>
        <!--定义普通列的封装规则-->
        <result column="user_name" property="userName"></result>
        <!--其他不指定的列会自动封装。-->
    </resultMap>

    <!--//测试resultMap的封装的-->
    <select id="findUserByResultMap" resultMap="MyUser">
        select * from user where  id = #{id}
    </select>

测试类代码:

@Test//这里我使用的是junit5的jupiter单元测试
    public void testResultMap() throws IOException {
        //获取核心对象SqlSessionFactory对象
        String sources = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(sources);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取和数据库的一次sql会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.findUserByResultMap(1);
        System.out.println("测试resultMap的封装的:"+user);
        //将这次会话提交后关闭
        sqlSession.commit();
        sqlSession.close();
    }

打印结果:
测试resultMap的封装的:User(id=1, userName=张三, addr=西安, age=28, birthday=Mon Apr 05 00:00:00 GMT+08:00 2021)

联合查询:级联属性封装结果集(不推荐)(ResultMap):

实体类Emp(映射主表用的):

package com.fan.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
    private Integer id;
    private String lastName;
    private String email;
    private String gender;
    private Department dept;
}

Department 部门类(映射从表用的):

package com.fan.domain;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Department {
    private Integer id;
    private String departmentName;
}

数据库表:
在这里插入图片描述
在这里插入图片描述

mapper接口的方法EmpMapper.java:

package com.fan.mapper;
import com.fan.domain.Emp;

public interface EmpMapper {
    public Emp getEmpAndDept(Integer id);
}

sql映射文件:EmpMapper.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.fan.mapper.EmpMapper">
    
    <resultMap id="myEmp" type="com.fan.domain.Emp">
        <id column="id" property="id"></id>
        <result column="last_name" property="lastName"></result>
        <result column="gender" property="gender"></result>
        <result column="did" property="dept.id"></result>
        <result column="dept_name" property="dept.departmentName"></result>
    </resultMap>
    <!-- public Emp getEmpAndDept(Integer id);-->
    <select id="getEmpAndDept" resultMap="myEmp">
        SELECT e.id id ,e.last_name last_name,e.gender gender,e.d_id d_id,
        d.id did ,d.dept_name dept_name
        FROM emp e,dept d where e.d_id = d.id
        AND e.id=#{id}
    </select>
</mapper>

测试类:

import com.fan.domain.Emp;
import com.fan.domain.User;
import com.fan.mapper.EmpMapper;
import com.fan.mapper.UserMapper;
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 org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;

public class ResultMapTest {
    private SqlSessionFactory getSqlSessionFactory() throws IOException {
        String resources = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resources);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        return sqlSessionFactory;
    }
    @Test
    void testRestMap() throws IOException {
        String sources = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(sources);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取和数据库的一次sql会话
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        Emp empAndDept = mapper.getEmpAndDept(1);
        System.out.println("测试resultMap的封装的:"+empAndDept);
        System.out.println("测试resultMap的封装的:"+empAndDept.getDept());
        //将这次会话提交后关闭

        sqlSession.close();

    }
}

使用association(关联单个对象)定义关联对象的封装规则:

在这里插入图片描述
EmpMapper.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.fan.mapper.EmpMapper">
    
    <!--<resultMap id="myEmp" type="com.fan.domain.Emp">
        <id column="id" property="id"></id>
        <result column="last_name" property="lastName"></result>
        <result column="gender" property="gender"></result>
        <result column="did" property="dept.id"></result>
        <result column="dept_name" property="dept.departmentName"></result>
    </resultMap>-->

    <resultMap id="myEmp2" type="com.fan.domain.Emp">
        <id column="id" property="id"></id>
        <result column="last_name" property="lastName"></result>
        <result column="gender" property="gender"></result>
        <result column="email" property="email"></result>

        <association property="dept" javaType="com.fan.domain.Department">
            <id column="did" property="id"></id>
            <result column="dept_name" property="departmentName"></result>
        </association>
    </resultMap>
    <!-- public Emp getEmpAndDept(Integer id);-->
    <select id="getEmpAndDept" resultMap="myEmp2">
        SELECT e.id id ,e.last_name last_name,e.gender gender,e.d_id d_id,
        d.id did ,d.dept_name dept_name
        FROM emp e,dept d where e.d_id = d.id
        AND e.id=#{id}
    </select>
</mapper>

注意:association (关联/联合)可以指定联合的javebean对象
property=“dept”:指定哪个属性是联合的对象。
javaType=“com.fan.domain.Department”:指定这个属性对象的类型【不能省略】

使用association (关联单个对象)进行分步查询(推荐使用):

在这里插入图片描述

在这里插入图片描述


效果展示:
在这里插入图片描述

代码演示一:查询emp表:
(1)实体类Emp:

package com.fan.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Emp {
    private Integer id;

    private String lastName;

    private String email;

    private String gender;//性别是String类型

    //private Integer dId;其他封装会不会缺少这个出现问题
    //每个员工有一个部门
    private Dept dept;

}

(2)EmpMapper接口:

List<Emp> selectByEmp(Emp emp);

(3)EmpMapper.xml(sql映射文件):

<!-- ***************尽量自定义resultMap ,这样避免出错***************-->
  <resultMap id="myEmp1" type="com.fan.domain.Emp">
    <id column="id" property="id"></id>
    <result column="last_name" property="lastName"></result>
    <result column="email" property="email"></result>
    <result column="gender" property="gender"></result>
    <!--单个对象的封装-->
    <association column="d_id" property="dept"  select="com.fan.mapper.DeptMapper.selectByPrimaryKey" >
    </association>
  </resultMap>

  <sql id="Base_Column_List">
    id, last_name, email, gender, d_id
  </sql>
  
<!--List<Emp> selectByEmp(Emp emp)-->
  <select id="selectByEmp" resultMap="myEmp1">
    select <include refid="Base_Column_List"></include>
    from emp
    <where>

      <if test="lastName!=null and lastName !='' ">
        <bind name="lastName" value=" '%' + lastName + '%' "/>
      </if>

      <if test="email!=null and email!=''">
        <bind name="email" value="'%'+email+'%'"/>
      </if>

      <if test="id!=null">
        and id = #{id}
      </if>

      <if test="lastName!=null and lastName!='' " >
        and last_name like #{lastName}
      </if>
      <if test="email!=null and email!='' ">
        and email like #{email}
      </if>
      <if test="gender!=null and gender!='' ">

        and gender = #{gender}
      </if>
    </where>
  </select>

需要结合部门表进行分步查询:

(1)Dept类:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dept {
    private Integer deptId;

    private String deptName;
    //每一个部门下有很多员工
    private List<Emp> emps;
}

(2)DeptMapper接口:

    //根据部门编号查出部门信息(这里不包含员工emps属性)
    Dept selectByPrimaryKey(Integer deptId);

(3)需要其他sql进行分步查询(DeptMapper.xml):

  <sql id="Base_Column_List">
    dept_id, dept_name
  </sql>
  <!--使用自己定义的封装的结果集到实体类resultMap-->
 <resultMap id="BaseResultMap2" type="com.fan.domain.Dept">
    <id column="dept_id" property="deptId"></id>
    <result column="dept_name" property="deptName"></result>
  </resultMap>
  
  <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap2">
    select 
    <include refid="Base_Column_List" />
    from dept
    where dept_id = #{deptId,jdbcType=INTEGER}
  </select>

(4)EmpController测试:

package com.fan.controller;
import com.fan.domain.Emp;
import com.fan.service.EmpService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import javax.annotation.Resource;
import java.util.List;

@Controller
public class EmpController {
    
    @Resource
    private EmpService empService;

    /*模糊查询*/
    @PostMapping("/likeSearch")
    public String selectByEmp(Emp emp, Model model){
        System.out.println("form表单参数:"+emp);
        if(emp.getGender().equals("男")){
            emp.setGender("1");
        }
        if(emp.getGender().equals("女")){
            emp.setGender("0");
        }
        List<Emp> emps = empService.selectByEmp(emp);

        model.addAttribute("emps",emps);
        for (Emp emp1 : emps) {
            System.out.println("$$"+emp1);
        }
        return "table/dynamic_table2";
    }

}

(5)页面取值:

<tr class="gradeX" th:each="emp,state : ${emps}">
    <th th:text="${state.count}">#</th>
    <th th:text="${emp.id}">ID</th>
    <th th:text="${emp.lastName}">用户名</th>
    <th th:text="${emp.email}" class="hidden-phone">邮箱</th>
    <th th:text="${emp.gender=='1'}?'男':'女' " class="hidden-phone">性别</th>
    <th th:text="${emp.dept.deptName}" class="hidden-phone">部门</th>
</tr>


其他案例代码演示二:

EmpMapper的接口:

package com.fan.mapper;
import com.fan.domain.Emp;

public interface EmpMapper {
    //分步查询的接口方法
    public Emp getEmpAndDeptByStep(Integer id);
}

EmpMapper.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.fan.mapper.EmpMapper">
    
    <resultMap id="myEmp3" type="com.fan.domain.Emp">
        <id column="id" property="id"></id>
        <result column="last_name" property="lastName"></result>
        <result column="gender" property="gender"></result>
        <!--select:表明当前属性是调用select指定的方法查出的结果
        colume:指定将哪一列的值作为参数传给这个方法。-->
         <!--我们类比javabean去设置,(类型 属性 ),column相当于主表的外键,-->
        <!--d_id是emp表中关联dept表的d_id(外键)值,并传参给DeptMapper中定义的getDeptById(Integer id)-->
        <association property="dept"
                     select="com.fan.mapper.DeptMapper.getDepartmentById"
                     column="d_id"></association>
    </resultMap>
	<!--public Emp getEmpAndDeptByStep(Integer id);-->
    <select id="getEmpAndDeptByStep" resultMap="myEmp3">
    /*分步查询这里的sql就很简单*/
    select * from emp where id = #{id}
    </select>
</mapper>

DeptMapper 的接口:

package com.fan.mapper;
import com.fan.domain.Department;

public interface DeptMapper {
    public Department getDepartmentById(Integer id);
}

DeptMapper 接口的实现:DeptMapper .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.fan.mapper.DeptMapper">
    <select id="getDepartmentById" resultType="com.fan.domain.Department">
        select id ,dept_name departmentName from dept where id = #{id}
    </select>
</mapper>

注意上面的两个是用来为分步查询做铺垫的。


测试分步查询:

 @Test
    void testRestMap() throws IOException {
        String sources = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(sources);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取和数据库的一次sql会话
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        Emp empAndDeptByStep = mapper.getEmpAndDeptByStep(1);
        System.out.println("分步查询:"+empAndDeptByStep);
        System.out.println("分步查询部门信息:"+empAndDeptByStep.getDept());
        //将这次会话提交后关闭
        sqlSession.close();
    }

结果:
在这里插入图片描述

分步查询之延迟加载/懒加载:

在这里插入图片描述

在这里插入图片描述
开启懒加载,需要设置以下两个:

<!--延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--按需加载,true表示如果对具有懒加载特性的对象的任意调用会导致这个对象的完整加载,false表示每种属性按照需要加载。-->
<setting name="aggressiveLazyLoading" value="false"/>

测试:

Emp empAndDeptByStep = mapper.getEmpAndDeptByStep(1);
        //当我们不用部门信息的时候,就不会多发送sql语句
        System.out.println("分步查询:"+empAndDeptByStep.getLastName());

测试结果:
在这里插入图片描述
当我们需要打印部门信息的时候:

//延迟加载的测试:当我们不用部门信息的时候,就不会多发送sql语句
 System.out.println("分步查询:"+empAndDeptByStep.getLastName());
 //延迟加载的测试:
 System.out.println("分步查询:"+empAndDeptByStep.getDept());

在这里插入图片描述

collection(关联集合)关联集合封装规则:

collection嵌套结果集的方式,定义关联的集合类型元素的封装

需求,在查询部门的时候将所有的此部门的员工也查询出来:

第一步:在部门的类中添加员工集合的属性:

package com.fan.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Department {
    private Integer id;
    private String departmentName;
    private List<Emp> emps;
}

在这里插入图片描述

DepeMapper.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.fan.mapper.DeptMapper">
    <select id="getDepartmentById" resultType="com.fan.domain.Department">
        select id ,dept_name departmentName from dept where id = #{id}
    </select>

    <resultMap id="MyDept" type="com.fan.domain.Department">
        <!--
         private Integer id;
        private String departmentName;
        private List<Emp> emps;
       注意,这里的数据库字段全部用的是查出来显示的字段
        -->
        <id column="did" property="id"></id>
        <result column="dept_name" property="departmentName"></result>
        <!--封装一个集合emps-->
        <collection property="emps" ofType="com.fan.domain.Emp">
            <!--定义集合中元素的封装规则-->
            <id column="eid" property="id"></id>
            <result column="last_name" property="lastName"/>
            <result column="email" property="email"></result>
            <result column="gender" property="gender"></result>
        </collection>
    </resultMap>
    <select id="getDept_EmpsById" resultMap="MyDept">
        SELECT d.id did ,d.dept_name dept_name ,
        e.id eid,e.last_name last_name,e.email email,e.gender gender
        FROM dept d
        LEFT JOIN emp e
        ON d.id = e.d_id
        where d.id = #{id}
    </select>
</mapper>

在这里插入图片描述
测试:

import com.fan.domain.Department;
import com.fan.mapper.DeptMapper;
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 org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;

public class ColectionResultMapTest {
   private SqlSessionFactory getSqlSessionFactory() throws IOException {
       String resource = "mybatis-config.xml";
       InputStream inputStream = Resources.getResourceAsStream(resource);
       SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
       return sqlSessionFactory;
   }
   @Test
   public void test01() throws IOException {
       //1.获取mybatis的核心对象sqlsessionFactory
       SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
       //获取sql对话
       SqlSession sqlSession = sqlSessionFactory.openSession(true);
       DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
       Department dept_empsById = mapper.getDept_EmpsById(1);
       System.out.println(dept_empsById);
       System.out.println(dept_empsById.getEmps().toString());
       sqlSession.close();
   }
}

collection (关联集合)使用分步查询(推荐使用):

分步查询:

  1. 首先,可以在部门表中根据部门编号查出部门信息:select * from dept where dept_id =1
  2. 然后,在员工表中根据员工的部门编号,查出多条员工记录:select * from emp where d_id =1

注意:分步查询的第二步要特别小心:我们得到部门信息后,根据部门的主键(关联的是emp的外键)去查找员工,一定注意用的是外键查询员工
然后根据上面两个执行的顺序写接口方法等。

第一步:在部门表中根据部门编号查出部门信息
DeptMapper.java :

package com.fan.mapper;
import com.fan.pojo.Dept;
import com.fan.pojo.Emp;
import java.util.List;
public interface DeptMapper {
	//根据部门id查出部门信息
    public Dept getDeptByIdStep(Integer id);
}

对应的sql映射文件:DeptMapper.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.fan.mapper.DeptMapper">

    <!--实体类的封装规则-->
    <resultMap id="myDept1" type="com.fan.pojo.Dept">
        <id column="dept_id" property="deptId"></id>
        <result column="dept_name" property="deptName"></result>
        <!--部门类中有多个员工,将我们查出来的dept_id的值再作为下一步查询的条件-->
        <collection  ofType="com.fan.pojo.Emp" property="emps"
             select="com.fan.mapper.EmpPlusMapper.getEmpsByDeptIdStep" column="dept_id">
        </collection>
    </resultMap>
   
    <!--Dept getDeptByIdStep(Integer id):查询部门,然后捎带查出部门下的所有员工-->
    <select id="getDeptByIdStep" resultMap="myDept1">
        select * from dept where dept_id = #{dept_id}
    </select>

</mapper>

可以先将以上代码中的select="" column="" 空着,等分步查询完成后,补上这两个信息。

在这里插入图片描述

第二步,在员工表中,按照部门id(emp的外键)查出所有员工的值(设计上一个select语句空白的地方):
EmpPlusMapper.java:

package com.fan.mapper;
import com.fan.pojo.Emp;
import java.util.List;
//测试关联查询:重点
public interface EmpPlusMapper {
	//根据部门编号查询员工,返回集合
    public List<Emp> getEmpsByDeptIdStep(Integer id);
}

对应的sql映射:EmpPlusMapper.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.fan.mapper.EmpPlusMapper">

    <!--List<Emp> getEmpsByDeptIdStep(Integer id),这个相当于从表了-->
    <select id="getEmpsByDeptIdStep" resultType="emp">
        select * from emp where d_id = #{dept_id}
    </select>
</mapper>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

测试:

 @Test//测试查询部门及其部门下的所有员工
    public void test04() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession sqlSession = sqlSessionFactory.openSession();
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        Dept deptByIdStep = mapper.getDeptByIdStep(1);
        System.out.println(deptByIdStep);
        System.out.println("*****************");
        System.out.println(deptByIdStep.getEmps());
    }

测试结果:
在这里插入图片描述

注意collection 标签中的column是将此result中的哪一列的值传给此collection 标签中select语句

扩展:
在这里插入图片描述

延迟加载和懒加载:

1.全局的延迟加载,lazyLoadingEnabled:

懒加载针对什么使用的?为什么要用懒加载?
懒加载针对级联使用的,懒加载的目的是减少内存的浪费和减轻系统负担。
懒加载是什么?
你可以理解为按需加载,当我调用到关联的数据时才与数据库交互否则不交互。

如何使用开启懒加载?
在mybatis的主配置文件的Setings标签开启。

<settings>
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

2.局部的延迟加载,fetchType:

fetchType 是可选的,在collection标签中使用,有效值为 lazy(延迟加载)和eager(立即加载),如果使用,它将取代(覆盖)全局配置参数lazyLoadingEnabled

在这里插入图片描述

鉴别器的使用:

在EmpMapper.xml中演示:

 <!--鉴别器的使用,查出员工的时候也把部门给查出来-->
    <!--type:声明我们要封装的类型-->
    <resultMap id="myStepEmp" type="com.fan.domain.Emp">
        <id column="id" property="id"></id>
        <result column="last_name" property="lastName"></result>
        <result column="email" property="email"></result>
        <result column="gender" property="gender"></result>
        <!--column:指定需要判定的列名,javaType:列值对应的java类型-->
        <discriminator javaType="string" column="gender">
            <!--女生resultType:指定封装的结果类型,不能缺少
            如果是女生,把女生所在的部门查出来-->
            <case value="0" resultType="emp">
                <association property="dept"
                             select="com.fan.mapper.DeptMapper.getDeptByDid"
                             column="d_id">
                </association>
            </case>
            <!--男生resultType:指定封装的结果类型,不能缺少
            如果是男生,把last_name这一列的值赋值给email
            -->
            <case value="1" resultType="emp">
                <id column="id" property="id"></id>
                <result column="last_name" property="lastName"></result>
                <result column="last_name" property="email"></result>
                <result column="gender" property="gender"></result>
            </case>
        </discriminator>
    </resultMap>
    
    <select id="getEmpDeptByStep" resultMap="myStepEmp">
        select * from emp where id = #{id}
    </select>

测试不变,使用上一个代码:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值