Mybatis(第二篇:联表查询)

导读:本篇文章讲解 Mybatis(第二篇:联表查询),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

Mybatis(第二篇:联表查询)

一、前期 项目的搭建

1.数据库

user.sql

/*
 Navicat MySQL Data Transfer

 Source Server         : localhost_3306
 Source Server Type    : MySQL
 Source Server Version : 50736
 Source Host           : localhost:3306
 Source Schema         : demo

 Target Server Type    : MySQL
 Target Server Version : 50736
 File Encoding         : 65001

 Date: 17/06/2022 09:52:53
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `age` int(11) NULL DEFAULT NULL,
  `sex` char(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `address` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `birthday` date NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, '小明', 20, '男', '武汉', '2022-06-10');
INSERT INTO `user` VALUES (2, '小红', 18, '女', '深圳', '2022-06-08');
INSERT INTO `user` VALUES (3, '小丽', 17, '女', '北京', '2019-12-02');

SET FOREIGN_KEY_CHECKS = 1;

department.sql

/*
 Navicat MySQL Data Transfer

 Source Server         : localhost_3306
 Source Server Type    : MySQL
 Source Server Version : 50736
 Source Host           : localhost:3306
 Source Schema         : crm

 Target Server Type    : MySQL
 Target Server Version : 50736
 File Encoding         : 65001

 Date: 20/06/2022 17:33:24
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for department
-- ----------------------------
DROP TABLE IF EXISTS `department`;
CREATE TABLE `department`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `sn` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of department
-- ----------------------------
INSERT INTO `department` VALUES (1, '总经办2', 'General Deparment2');
INSERT INTO `department` VALUES (2, '人力资源部', 'Human Resources Department');
INSERT INTO `department` VALUES (3, '采购部', 'Order Department');
INSERT INTO `department` VALUES (4, '仓储部', 'Warehousing Department');
INSERT INTO `department` VALUES (6, '技术部', 'Technolog Department ');

SET FOREIGN_KEY_CHECKS = 1;

employee.sql

/*
 Navicat MySQL Data Transfer

 Source Server         : localhost_3306
 Source Server Type    : MySQL
 Source Server Version : 50736
 Source Host           : localhost:3306
 Source Schema         : crm

 Target Server Type    : MySQL
 Target Server Version : 50736
 File Encoding         : 65001

 Date: 20/06/2022 17:33:32
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for employee
-- ----------------------------
DROP TABLE IF EXISTS `employee`;
CREATE TABLE `employee`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `email` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `age` int(11) NULL DEFAULT NULL,
  `admin` bit(1) NULL DEFAULT NULL,
  `dept_id` bigint(20) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 20 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of employee
-- ----------------------------
INSERT INTO `employee` VALUES (1, 'admin', '$2a$10$kYaoE4sx1uweWHoJt1CExO7ZpaM4Akt4rPnOcXK9/KRWxRuuEIfWC', 'admin@abc.com', 20, b'1', 2);
INSERT INTO `employee` VALUES (2, 'zhao', '$2a$10$kYaoE4sx1uweWHoJt1CExO7ZpaM4Akt4rPnOcXK9/KRWxRuuEIfWC', 'zhaoz@wolfcode.cn', 35, b'0', 1);
INSERT INTO `employee` VALUES (3, '赵一明', 'c4ca4238a0b923820dcc509a6f75849b', 'zhaoym@wolfcode.cn', 25, b'0', 1);
INSERT INTO `employee` VALUES (4, '钱总', 'c4ca4238a0b923820dcc509a6f75849b', 'qianz@wolfcode.cn', 35, b'0', 2);
INSERT INTO `employee` VALUES (5, '钱二明', 'c4ca4238a0b923820dcc509a6f75849b', 'qianem@wolfcode.cn', 25, b'0', 2);
INSERT INTO `employee` VALUES (6, '孙总', 'c4ca4238a0b923820dcc509a6f75849b', 'sunz@wolfcode.cn', 35, b'0', 3);
INSERT INTO `employee` VALUES (7, '孙三明', 'c4ca4238a0b923820dcc509a6f75849b', 'sunsm@wolfcode.cn', 25, b'0', 3);
INSERT INTO `employee` VALUES (9, '李四明', 'c4ca4238a0b923820dcc509a6f75849b', 'lism@wolfcode.cn', 25, b'0', 4);
INSERT INTO `employee` VALUES (10, '周总', 'c4ca4238a0b923820dcc509a6f75849b', 'zhouz@wolfcode.cn', 35, b'0', 5);
INSERT INTO `employee` VALUES (11, '周五明', 'c4ca4238a0b923820dcc509a6f75849b', 'zhouwm@wolfcode.cn', 25, b'0', 5);
INSERT INTO `employee` VALUES (12, '吴总', 'c4ca4238a0b923820dcc509a6f75849b', 'wuz@wolfcode.cn', 35, b'0', 6);
INSERT INTO `employee` VALUES (13, '吴六明', 'c4ca4238a0b923820dcc509a6f75849b', 'wulm@wolfcode.cn', 25, b'0', 6);
INSERT INTO `employee` VALUES (14, '郑总', 'c4ca4238a0b923820dcc509a6f75849b', 'zhengz@wolfcode.cn', 35, b'0', 7);
INSERT INTO `employee` VALUES (15, '郑七明', 'c4ca4238a0b923820dcc509a6f75849b', 'zhengqm@wolfcode.cn', 25, b'0', 7);
INSERT INTO `employee` VALUES (16, '孙四明', 'c4ca4238a0b923820dcc509a6f75849b', 'sunsim@wolfcode.cn', 25, b'0', 3);
INSERT INTO `employee` VALUES (17, '孙五明2', 'c4ca4238a0b923820dcc509a6f75849b', 'sunwm@wolfcode.cn', 25, b'0', 1);
INSERT INTO `employee` VALUES (18, '李五明', 'c4ca4238a0b923820dcc509a6f75849b', 'liwm@wolfcode.cn', 25, b'0', 4);
INSERT INTO `employee` VALUES (19, '李六明', 'c4ca4238a0b923820dcc509a6f75849b', 'lilm@wolfcode.cn', 25, b'0', 4);

SET FOREIGN_KEY_CHECKS = 1;

role.sql

/*
 Navicat MySQL Data Transfer

 Source Server         : localhost_3306
 Source Server Type    : MySQL
 Source Server Version : 50736
 Source Host           : localhost:3306
 Source Schema         : crm

 Target Server Type    : MySQL
 Target Server Version : 50736
 File Encoding         : 65001

 Date: 20/06/2022 17:33:49
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for role
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `sn` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 15 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES (1, '人事管理', 'HR_MGR');
INSERT INTO `role` VALUES (2, '采购管理', 'ORDER_MGR');
INSERT INTO `role` VALUES (3, '仓储管理', 'WAREHOUSING_MGR');
INSERT INTO `role` VALUES (4, '行政部管理', 'Admin_MGR');
INSERT INTO `role` VALUES (11, '市场经理', 'Market_Manager');
INSERT INTO `role` VALUES (12, '市场专员', 'Market');
INSERT INTO `role` VALUES (13, '2222222', '22222222');
INSERT INTO `role` VALUES (14, '1231', '3132');

SET FOREIGN_KEY_CHECKS = 1;

employee_role.sql

/*
 Navicat MySQL Data Transfer

 Source Server         : localhost_3306
 Source Server Type    : MySQL
 Source Server Version : 50736
 Source Host           : localhost:3306
 Source Schema         : crm

 Target Server Type    : MySQL
 Target Server Version : 50736
 File Encoding         : 65001

 Date: 20/06/2022 17:33:41
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for employee_role
-- ----------------------------
DROP TABLE IF EXISTS `employee_role`;
CREATE TABLE `employee_role`  (
  `employee_id` bigint(20) NULL DEFAULT NULL,
  `role_id` bigint(20) NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of employee_role
-- ----------------------------
INSERT INTO `employee_role` VALUES (2, 1);
INSERT INTO `employee_role` VALUES (3, 12);
INSERT INTO `employee_role` VALUES (5, 11);
INSERT INTO `employee_role` VALUES (22, 11);
INSERT INTO `employee_role` VALUES (22, 12);
INSERT INTO `employee_role` VALUES (23, 3);
INSERT INTO `employee_role` VALUES (23, 4);
INSERT INTO `employee_role` VALUES (23, 11);
INSERT INTO `employee_role` VALUES (23, 12);
INSERT INTO `employee_role` VALUES (17, 1);
INSERT INTO `employee_role` VALUES (17, 2);
INSERT INTO `employee_role` VALUES (17, 3);
INSERT INTO `employee_role` VALUES (17, 4);
INSERT INTO `employee_role` VALUES (17, 11);
INSERT INTO `employee_role` VALUES (17, 12);
INSERT INTO `employee_role` VALUES (17, 13);

SET FOREIGN_KEY_CHECKS = 1;

2.IDEA项目架构搭建

在这里插入图片描述

2.1 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.bjpowernode</groupId>
    <artifactId>02_realtionproject</artifactId>
    <version>1.0.0</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.9</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
        </dependency>
        <!--log-->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.13.3</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <!-- 分页插件jar -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.2.0</version>
        </dependency>
    </dependencies>


</project>

2.2 domain包

2.2.1 Department.java
package com.bjpowernode.domain;
import lombok.Data;

@Data
public class Department {
    private Long id;
    private String name;
    private String sn;

}
2.2.2 Employee.java
package com.bjpowernode.domain;

import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.util.ArrayList;
import java.util.List;

@Getter
@Setter
public class Employee {

    private Long id;
    private String username;
    private String name;
    private String password;
    private String email;
    private Integer age;
    private boolean admin;
    private Department dept; // 所属部门
    private List<Role> roles =new ArrayList(); //拥有的角色

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", name='" + name + '\'' +
                ", password='" + password + '\'' +
                ", email='" + email + '\'' +
                ", age=" + age +
                ", admin=" + admin +
                ", dept=" + dept +
                '}';
    }
}
2.2.3 Role.java
package com.bjpowernode.domain;

import lombok.Data;

@Data
public class Role {
    private Long id;
    private String name;
    private String sn;
}

2.3 util包

MybatisUtil.java
 package com.bjpowernode.util;

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;
import java.io.InputStream;

public class MyBatisUtil {

    private MyBatisUtil(){}

    private static SqlSessionFactory factory ;
    static {
        try {
            InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
            factory=  new SqlSessionFactoryBuilder().build(resourceAsStream);

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static SqlSession openSession() {
        return factory.openSession(true);
    }
}

2.4 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="db.properties"/>

    <!--设置日志-->
    <settings>
        <setting name="logImpl" value="LOG4J"/>
        <!-- 设置为 false 表示每个延迟加载属性会按需加载 -->
        <setting name="aggressiveLazyLoading" value="false" />
        <!--是否开启懒加载 总开关 延迟加载的全局开关-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--指定对象的哪些方法触发一次延迟加载-->
        <setting name="lazyLoadTriggerMethods" value="clone"/>
    </settings>

    <!--给所有的 javaBean 起别名-->
    <typeAliases>
        <package name="com.bjpowernode.domain"/>
    </typeAliases>


    <!--分页插件的 配置-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!--通过这个配置,来动态添加分页的功能-->
            <property name="helperDialect" value="mysql"/>
            <!--通过pageSizeZero属性可以灵活处理分页 当pageSize 设置为0
             就查询全部数据-->
            <property name="pageSizeZero" value="true"/>
            <!--通过reasonable 属性 可以合理化分页-->
            <property name="reasonable" value="true"/>
        </plugin>
    </plugins>

    <!--配置环境-->
    <environments default="dev">
        <environment id="dev">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driverClassName}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--挂载sql 的映射文件-->
    <mappers>
        <mapper resource="com/bjpowernode/mapper/DepartmentMapper.xml"/>
        <mapper resource="com/bjpowernode/mapper/EmployeeMapper.xml"/>
        <mapper resource="com/bjpowernode/mapper/RoleMapper.xml"/>
    </mappers>

</configuration>

2.5 db.properties

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///rbac?useSSL=false
username=root
password=kong1234

2.6 log4j.properties

log4j.rootLogger=ERROR, stdout

log4j.logger.com.bjpowernode.mapper=TRACE

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

2.7 mapper包

2.7.1 departmentMapper.java
package com.bjpowernode.mapper;

import com.bjpowernode.domain.Department;

import java.util.List;

public interface DepartmentMapper {

    List<Department>  selectAll();

    // 根据id 查询部门
    Department selectDeptById();
}
2.7.2 EmployeeMapper.java
package com.bjpowernode.mapper;

import com.bjpowernode.domain.Employee;

import java.util.List;

public interface EmployeeMapper {

    List<Employee>  selectAll();

    // 关联查询
    List<Employee> selectEmpWithDepart();

    // 额外sql
    List<Employee> selectEmpWithDepart2();

    // 额外sql
    List<Employee> selectEmpWithRoles();

}
2.7.3 RoleMapper.java
package com.bjpowernode.mapper;

import com.bjpowernode.domain.Department;
import com.bjpowernode.domain.Role;

import java.util.List;

public interface RoleMapper {

    List<Role>  selectAll();

    List<Role> selectRolesByEmpId(Long empId);

}

2.8 xml

2.8.1 DepartmentMapper.xml
部分代码说明——resultMap的两种写法

写法一:

  <resultMap id="baseMap" type="employee">
        <id column="id" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="email" property="email"/>
        <result column="age" property="age"/>
        <result column="admin" property="admin"/>
        <!--
            association用来封装对象属性的
            property 对象属性的名称(module层外键的那个属性 Employee的外键属性)
            javaType 对象属性的全限定名 (外键属性的全限定名)
        -->
        <!--		<association property="department" javaType="com.bjpowernode.domain.Department">-->
        <!--			<id column="d_id" property="id"/>-->
        <!--			<result column="d_name" property="name"/>-->
        <!--		</association>-->

        <association property="department" javaType="com.bjpowernode.domain.Department" columnPrefix="d_">
            <id column="id" property="id"/>
            <result column="name" property="name"/>
        </association>
    </resultMap>

写法二:

 <resultMap id="baseMap" type="employee">
        <id column="id" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="email" property="email"/>
        <result column="age" property="age"/>
        <result column="admin" property="admin"/>
        <result column="d_id" property="department.id"/>
        <result column="d_name" property="department.name"/>
    </resultMap>
全部代码
<?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.bjpowernode.mapper.DepartmentMapper">
  <select id="selectAll" resultType="department">
  select * from department
</select>

<select id="selectDeptById" resultType="department">
   select * from department where id = #{id}
</select>

</mapper>
2.8.2 EmployeeMapper.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.bjpowernode.mapper.EmployeeMapper">
  <select id="selectAll" resultType="employee">
  select * from employee
</select>

<!--    <resultMap id="baseMap" type="employee">-->
<!--        <id column="id" property="id"/>-->
<!--        <result column="username" property="username"/>-->
<!--        <result column="password" property="password"/>-->
<!--        <result column="email" property="email"/>-->
<!--        <result column="age" property="age"/>-->
<!--        <result column="admin" property="admin"/>-->
<!--        &lt;!&ndash;-->
<!--            association用来封装对象属性的-->
<!--            property 对象属性的名称(module层外键的那个属性 Employee的外键属性)-->
<!--            javaType 对象属性的全限定名 (外键属性的全限定名)-->
<!--        &ndash;&gt;-->
<!--        &lt;!&ndash;		<association property="department" javaType="com.bjpowernode.domain.Department">&ndash;&gt;-->
<!--        &lt;!&ndash;			<id column="d_id" property="id"/>&ndash;&gt;-->
<!--        &lt;!&ndash;			<result column="d_name" property="name"/>&ndash;&gt;-->
<!--        &lt;!&ndash;		</association>&ndash;&gt;-->

<!--        <association property="department" javaType="com.bjpowernode.domain.Department" columnPrefix="d_">-->
<!--            <id column="id" property="id"/>-->
<!--            <result column="name" property="name"/>-->
<!--        </association>-->
<!--    </resultMap>-->

    <resultMap id="baseMap" type="employee">
        <id column="id" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="email" property="email"/>
        <result column="age" property="age"/>
        <result column="admin" property="admin"/>
        <result column="d_id" property="department.id"/>
        <result column="d_name" property="department.name"/>
    </resultMap>


<select id="selectEmpWithDepart" resultMap="baseMap">
select emp.id,emp.name,emp.username,emp.age,emp.admin, emp.email,emp.`password`,
dept.id d_id, dept.name d_name
from  employee emp left join department dept on emp.dept_id = dept.id
</select>


<resultMap id="baseMap2" type="employee">
 <id column="id" property="id" />
  <result column="username" property="username"/>
  <result column="name" property="name"/>
  <result column="password" property="password"/>
  <result column="email" property="email"/>
  <result column="age" property="age"/>
  <result column="admin" property="admin"/>
  <!--
     column 属性 它是发送 额外sql的  条件
     select 属性 它是指定发送额外sql的方法
  -->
  <association property="dept" column="dept_id"
       select="com.bjpowernode.mapper.DepartmentMapper.selectDeptById"/>

</resultMap>

<select id="selectEmpWithDepart2" resultMap="baseMap2">
  select * from employee
</select>


<resultMap id="baseMap3" type="employee">
 <id column="id" property="id" />
  <result column="username" property="username"/>
  <result column="name" property="name"/>
  <result column="password" property="password"/>
  <result column="email" property="email"/>
  <result column="age" property="age"/>
  <result column="admin" property="admin"/>
  <!--
  collection  封装集合类型的属性
     property 表示 集合类型的属性的名称
     ofType 表示集合中存储的对象的类型
     select 表示 指定发送的额外sql
     column  表示 执行额外sql 需要的条件
    -->
  <collection property="roles" ofType="com.bjpowernode.domain.Role"
    select="com.bjpowernode.mapper.RoleMapper.selectRolesByEmpId"
     column="id"/>

</resultMap>


<select id="selectEmpWithRoles" resultMap="baseMap3">
select * from employee
</select>

</mapper>
2.8.3 RoleMapper.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.bjpowernode.mapper.RoleMapper">
  <select id="selectAll" resultType="role">
  select * from role
</select>

<select id="selectRolesByEmpId" resultType="role">
select r.* from role r join employee_role er on r.id = er.role_id
where er.employee_id = #{empId}
</select>


</mapper>

2.9 测试类

package com.bjpowernode.test;

import com.bjpowernode.domain.Department;
import com.bjpowernode.domain.Employee;
import com.bjpowernode.mapper.DepartmentMapper;
import com.bjpowernode.mapper.EmployeeMapper;
import com.bjpowernode.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class DemoTest {


    // 需求: 查询所有的部门信息
    @Test
    public  void testSelectAll(){
        SqlSession sqlSession = MyBatisUtil.openSession();
        DepartmentMapper mapper = sqlSession.getMapper(DepartmentMapper.class);
        List<Department> departments = mapper.selectAll();
        departments.forEach(System.out::println);
        sqlSession.close();
    }

    // 需求: 查询所有的员工信息
    @Test
    public  void testSelectAll1(){
        SqlSession sqlSession = MyBatisUtil.openSession();
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        List<Employee> employees = mapper.selectAll();
        employees.forEach(System.out::println);
        sqlSession.close();
    }

    //需求: 查询员工信息以及对应的部门信息 (员工信息和对应的部门信心 都要展示)

    @Test
    public  void testSelectEmpsWithDepart(){
        SqlSession sqlSession = MyBatisUtil.openSession();
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        List<Employee> employees = mapper.selectEmpWithDepart();
        employees.forEach(System.out::println);
        sqlSession.close();
    }

    @Test
    public  void testSelectEmpsWithDepart2(){
        SqlSession sqlSession = MyBatisUtil.openSession();
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        List<Employee> employees = mapper.selectEmpWithDepart2();
        employees.forEach(System.out::println);
        sqlSession.close();
    }

    // 需求:查询员工信息以及拥有的角色信息(员工信息 要展示)
    @Test
    public  void testSelectEmpsWithRoles(){
        SqlSession sqlSession = MyBatisUtil.openSession();
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        List<Employee> employees = mapper.selectEmpWithRoles();
        for (Employee employee : employees) {
            System.out.println(employee.getRoles());
        }
        sqlSession.close();
    }

    /**
     *  完成上述需求:有两种方案 ,一种是 关联查询,一种是 额外sql
     *  特点: 关联查询  只发送一条sql ,关联了多张表
     *        额外sql   发送 N + 1 条sql , 没有关联表
     *  优缺点:
     *
     *      如果需求中,查询员工以及部门信息,并要求展示在列表上,那么
     *      关联查询 方案比较好,而额外sql 方案 不可取,因为发送sql 太多,
     *      给 sql 服务器带来压力
     *
     *      如果需求中,查询员工信息以及部门信息,但是 要求展示员工信息,
     *      不需要展示部门信息  ,那么这个时候 应当使用 额外sql ,而放弃关联查询
     *      因为额外sql 可以
     *      配置懒加载模式(需要的时候,发送额外sql,不需要的时候,不发送),
     *      放弃关联查询 是由于关联表多 ,导致性能低
     *
     *
     *
     */
}

3. 过程知识点细讲

3.1 一对多封装 (一个员工对应一个部门)

Employee.java

package com.bjpowernode.domain;

import lombok.Data;

@Data
public class Employee {
    private Long id;
    private String username;
    private String password;
    private String email;
    private Integer age;
    private boolean admin;

    private Department department;// 所属部门

}

方案一:关联查询(association、property、javaType、[columnPrefix])

EmployeeMapper.java

 List<Employee> selectAllEmployeeWithDepartment();

EmployeeMapper.xml

association用来封装对象属性的
property 对象属性的名称(module层外键的那个属性 Employee的外键属性)
javaType 对象属性的全限定名 (外键属性的全限定名)

<resultMap id="baseMap" type="employee">
		<id column="id" property="id"/>
		<result column="username" property="username" />
		<result column="password" property="password" />
		<result column="email" property="email" />
		<result column="age" property="age" />
		<result column="admin" property="admin" />
<!--
	association用来封装对象属性的
	property 对象属性的名称(module层外键的那个属性 Employee的外键属性)
	javaType 对象属性的全限定名 (外键属性的全限定名)
-->
		<association property="department" javaType="com.bjpowernode.domain.Department">
			<id column="d_id" property="id"/>
			<result column="d_name" property="name"/>
		</association>
	</resultMap>
columnPrefix

用了columnPrefix属性

<resultMap id="baseMap" type="employee">
		<id column="id" property="id"/>
		<result column="username" property="username" />
		<result column="password" property="password" />
		<result column="email" property="email" />
		<result column="age" property="age" />
		<result column="admin" property="admin" />
<!--
	association用来封装对象属性的
	property 对象属性的名称(module层外键的那个属性 Employee的外键属性)
	javaType 对象属性的全限定名 (外键属性的全限定名)
-->
		<association property="department" javaType="com.bjpowernode.domain.Department" columnPrefix="d_">
			<id column="id" property="id"/>
			<result column="name" property="name"/>
		</association>
	</resultMap>
    <select id="selectAllEmployeeWithDepartment" resultMap="baseMap">
SELECT
	emp.id,
	emp.username,
	emp.age,
	emp.admin,
	emp.email,
	emp.`password`,
	dept.id d_id,
	dept.NAME d_name
FROM
	employee emp
	LEFT JOIN department dept ON emp.dept_id = dept.id

    </select>

方案二:发送额外sql(1)(推荐使用这种)

EmployeeMapper.java

   // 发送额外SQL
    List<Employee> selectAllEmployeeWithDepartmentBySendExtraSQL();

EmployeeMapper.xml

resultMap

column 属性 它是发送额外sql的条件
select 属性 它是指定发送额外sql的方法

<resultMap id="baseMapBySendExtraSQL" type="employee">
		<id column="id" property="id"/>
		<result column="username" property="username" />
		<result column="password" property="password" />
		<result column="email" property="email" />
		<result column="age" property="age" />
		<result column="admin" property="admin" />
		<!--
			column 属性 它是发送额外sql的条件
			select 属性 它是指定发送额外sql的方法
		-->
		<association property="department" column="dept_id"
		select="com.bjpowernode.mapper.DepartmentMapper.selectDepartmentById">
		</association>

	</resultMap>

select标签

<select id="selectAllEmployeeWithDepartmentBySendExtraSQL" resultMap="baseMapBySendExtraSQL">
		select * from employee;
	</select>

DepartmentMapper.java

  // 根据id 查询部门
    Department selectDepartmentById();

DepartmentMapper.xml

 <select id="selectDepartmentById" resultType="department">
        select * from department where id = #{id}
    </select>

方案二:发送额外sql(2)

EmployeeMapper.java

  // 发送额外SQL Tedu
    List<Employee> selectAllEmployeeWithDepartmentBySendExtraSQLTedu();

EmployeeMapper.xml

   <resultMap id="baseMapBySendExtraSQLTedu" type="employee">
        <id column="id" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="email" property="email"/>
        <result column="age" property="age"/>
        <result column="admin" property="admin"/>

        <!--
           column 属性 它是发送额外sql的条件
           select 属性 它是指定发送额外sql的方法
       -->
        <association property="department" column="dept_id"
                     select="selectDepartmentById">
        </association>
    </resultMap>

    <select id="selectDepartmentById" resultType="department">
         select * from department where id = #{id}
    </select>

    <select id="selectAllEmployeeWithDepartmentBySendExtraSQLTedu" resultMap="baseMapBySendExtraSQLTedu">
        select * from employee;
    </select>

测试类

   @Test
    public void selectAllEmployeeWithDepartmentBySendExtraSQLTedu(){
        SqlSession sqlSession = MyBatisUtil.openSession();
        EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
        List<Employee> employeeList = employeeMapper.selectAllEmployeeWithDepartmentBySendExtraSQLTedu();
        employeeList.forEach(System.out::println);
        sqlSession.close();
    }

两种方案的对比

/**
* 完成下述需求:有两种方案 ,一种是 关联查询,一种是 额外sql
* 特点: 关联查询 只发送一条sql ,关联了多张表
* 额外sql 发送 N + 1 条sql , 没有关联表
* 优缺点:
*
* 如果需求中,查询员工以及部门信息,并要求展示在列表上,那么
* 关联查询 方案比较好,而额外sql 方案 不可取,因为发送sql 太多,
* 给 sql 服务器带来压力
*
* 如果需求中,查询员工信息以及部门信息,但是 要求展示员工信息,
* 不需要展示部门信息 ,那么这个时候 应当使用 额外sql ,而放弃关联查询
* 因为额外sql 可以
* 配置懒加载模式(需要的时候,发送额外sql,不需要的时候,不发送),
* 放弃关联查询 是由于关联表多 ,导致性能低
*
*/

3.2 多对多封装(员工和角色)

domain
Role.java

package com.bjpowernode.domain;

import lombok.Data;

@Data
public class Role {
    private Long id;
    private String name;
    private String sn;
}

Employee.java表


```bash
package com.bjpowernode.domain;

import lombok.Data;

import java.util.*;

@Data
public class Employee {
    private Long id;
    private String username;
    private String password;
    private String email;
    private Integer age;
    private boolean admin;

    private Department department;// 所属部门

    private List<Role> roleList = new ArrayList<>();

}

RoleMapper.java

package com.bjpowernode.mapper;

import com.bjpowernode.domain.Department;
import com.bjpowernode.domain.Role;

import java.util.List;

public interface RoleMapper {

    List<Role> selectAllRole();
}

RoleMapper.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.bjpowernode.mapper.RoleMapper">


    <select id="selectAllRole" resultType="role">
        select * from role;
    </select>
</mapper>

mybatis-config.xml

 <!-- 挂载sql的映射文件   -->
    <mappers>
        <mapper resource="com.bjpowernode.mapper\DepartmentMapper.xml"/>
        <mapper resource="com.bjpowernode.mapper\EmployeeMapper.xml"/>
        <mapper resource="com.bjpowernode.mapper\RoleMapper.xml"/>
    </mappers>

测试类

@Test
public void selectAllRole(){
    SqlSession sqlSession = MyBatisUtil.openSession();
    RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
    List<Role> roleList = roleMapper.selectAllRole();
    roleList.forEach(System.out::println);
    sqlSession.close();
}

EmployeeMapper.java

// 发送额外SQL
List<Employee> selectAllEmployeeWithRole();

方案一:发送额外SQL (1)(推荐使用这种方式)

EmployeeMapper.xml

<resultMap id="EmpRoleMapBySendExtraSQL" type="employee">
		<id column="id" property="id"/>
		<result column="username" property="username" />
		<result column="password" property="password" />
		<result column="email" property="email" />
		<result column="age" property="age" />
		<result column="admin" property="admin" />
		<!--
			collection 封装集合类型的属性
			property 表示 集合类型的属性的名称(module层外键集合属性的名称)
			ofType 表示集合中存储的对象的类型
			select 表示 指定发送的额外sql
			column 表示 执行额外sql 需要的条件
		-->
		<collection property="roleList" ofType="com.bjpowernode.domain.Role"
		select="com.bjpowernode.mapper.RoleMapper.selectRolesByEmpId" column="id">

		</collection>

	</resultMap>

	<select id="selectAllEmployeeWithRole" resultMap="EmpRoleMapBySendExtraSQL">
		select * from employee;
	</select>

RoleMapper.java

   List<Role> selectRolesByEmpId(Long empId);

RoleMapper.xml

   <select id="selectRolesByEmpId" resultType="role">
        select r.* from role r join employee_role er on r.id = er.role_id
        where er.employee_id = #{empId}
</select>

测试类

  // 需求:查询员工信息以及拥有的角色信息(员工信息要展示)
    @Test
    public void selectAllEmployeeWithRole(){
        SqlSession sqlSession = MyBatisUtil.openSession();
        EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
        List<Employee> employeeList = employeeMapper.selectAllEmployeeWithRole();
        employeeList.forEach(System.out::println);
        sqlSession.close();
    }

发送了额外sql
在这里插入图片描述

是否发送额外SQL 配置懒加载

如何让它不发额外SQL呢?配置一个懒加载
将以下代码圈出来的代码复制到mybatis-config.xml文件中
在这里插入图片描述

<!-- 设置为 false 表示每个延迟加载属性会按需加载 -->
    <setting name="aggressiveLazyLoading" value="false" />
    <!--是否开启懒加载 总开关 延迟加载的全局开关-->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!--指定对象的哪些方法触发一次延迟加载-->
    <setting name="lazyLoadTriggerMethods" value="clone"/>

修改Employee.java
@Data改为@Getter和@Setter
重写toString方法(不重写roleList)

package com.bjpowernode.domain;

import lombok.Data;
import lombok.Getter;
import lombok.Setter;

import java.util.*;

@Getter
@Setter
public class Employee {
    private Long id;
    private String username;
    private String password;
    private String email;
    private Integer age;
    private boolean admin;

    private Department department;// 所属部门

    private List<Role> roleList = new ArrayList<>();

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", email='" + email + '\'' +
                ", age=" + age +
                ", admin=" + admin +
                ", department=" + department +
                '}';
    }
}

再次执行测试类
就没有发送额外SQL了
在这里插入图片描述
测试类
当测试类调用getRoleList的时候,就又会发送额外SQL了

 // 需求:查询员工信息以及拥有的角色信息(员工信息要展示)
    @Test
    public void selectAllEmployeeWithRole(){
        SqlSession sqlSession = MyBatisUtil.openSession();
        EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
        List<Employee> employeeList = employeeMapper.selectAllEmployeeWithRole();
        for (Employee employee : employeeList) {
            System.out.println(employee.getRoleList());
        }
        sqlSession.close();
    }

又会发送额外SQL了
在这里插入图片描述

方案一:发送额外SQL(2)

EmployeeMapper.java

// 发送额外SQL Tedu
    List<Employee> selectAllEmployeeWithRoleBySendExtraSQLTedu();

EmployeeMapper.xml

 <resultMap id="EmpRoleMapBySendExtraSQLTedu" type="employee">
        <id column="id" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="email" property="email"/>
        <result column="age" property="age"/>
        <result column="admin" property="admin"/>
        <!--
            collection 封装集合类型的属性
            property 表示 集合类型的属性的名称(module层外键 集合属性的名称)
            ofType 表示集合中存储的对象的类型
            select 表示 指定发送的额外sql接口权限定名
            column 表示 执行额外sql 需要的条件
        -->
        <collection property="roleList" ofType="com.bjpowernode.domain.Role"
                    select="selectRolesByEmpId" column="id">
        </collection>

    </resultMap>

    <select id="selectRolesByEmpId" resultType="role">
          select r.* from role r join employee_role er on r.id = er.role_id
        where er.employee_id = #{empId}
    </select>

    <select id="selectAllEmployeeWithRoleBySendExtraSQLTedu" resultMap="EmpRoleMapBySendExtraSQLTedu">
        select * from employee;
    </select>

测试类

 @Test
    public void selectAllEmployeeWithRoleBySendExtraSQuLTedu(){
        SqlSession sqlSession = MyBatisUtil.openSession();
        EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
        List<Employee> employeeList = employeeMapper.selectAllEmployeeWithRoleBySendExtraSQLTedu();
        for (Employee employee : employeeList) {
            System.out.println(employee.getRoleList());
        }
        sqlSession.close();
    }

方案二:关联查询

EmployeeMapper.java

   //关联查询
    List<Employee> selectAllEmployeeWithRole();

EmployeeMapper.xml

<resultMap id="EmpRoleMap" type="employee">
        <id column="id" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="email" property="email"/>
        <result column="age" property="age"/>
        <result column="admin" property="admin"/>
        <!--
            collection 封装集合类型的属性
            property 表示 集合类型的属性的名称(module层外键 集合属性的名称)
            ofType 表示集合中存储的对象的类型
            select 表示 指定发送的额外sql接口权限定名
            column 表示 执行额外sql 需要的条件
        -->
        <collection property="roleList" ofType="role" columnPrefix="r_">
            <id column="id" property="id"/>
            <result column="name" property="name"/>
        </collection>

    </resultMap>


    <select id="selectAllEmployeeWithRole" resultMap="EmpRoleMap">
SELECT
	emp.*,
	r.id r_id,
	r.NAME r_name
FROM
	employee emp
	JOIN employee_role er ON emp.id = er.employee_id
	JOIN role r ON r.id = er.role_id
	</select>

Emloyee.java

package com.bjpowernode.domain;

import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.util.*;

@Getter
@Setter
@ToString
public class Employee {
    private Long id;
    private String username;
    private String password;
    private String email;
    private Integer age;
    private boolean admin;

    private Department department;// 所属部门

    private List<Role> roleList = new ArrayList<>();

//    @Override
//    public String toString() {
//        return "Employee{" +
//                "id=" + id +
//                ", username='" + username + '\'' +
//                ", password='" + password + '\'' +
//                ", email='" + email + '\'' +
//                ", age=" + age +
//                ", admin=" + admin +
//                ", department=" + department +
//                '}';
//    }
}

测试类

@Test
public void selectAllEmployeeWithRole(){
    SqlSession sqlSession = MyBatisUtil.openSession();
    EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
    List<Employee> employeeList = employeeMapper.selectAllEmployeeWithRole();
    for (Employee employee : employeeList) {
        System.out.println(employee);
    }
    sqlSession.close();
}

总结

配置文件中 两个标签 :association collection 的选择
首先 标签 和 使用的查询方案 没有任何关系
如果类中有对象属性,则使用association标签
如果类中有集合对象属性,则使用 collection

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/85570.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!