mybatis 增删改查(关联查询、子对象集合:推荐)

mybatis持久层,与数据库打交道的 1 加载对应MySQL的jdbc的包

在这里插入图片描述
MySQL版本与jar包版本可以不一一对应

//数据池的插件,管理数据库与数据池之间的关系、有多少连接、连接该怎样去管理,如果直接使用MySQL单链接是用不到这个包的,但是一般没有单连接的工程
 <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.1.9</version>
    </dependency>
    //持久化的一个框架,mybatis
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>1.3.0</version>
    </dependency>
    //数据库jdbc的包,连接数据库的;
    //MySQL的这个包是放在整个工程的pom文件的,哪个模块使用就只引入groupId、artifactId即可
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.38</version>
    </dependency>

引入包后记得在mavenproject中刷新工程,将包导入成功
在以上3个包对应的模块下的mavenproject中能看到加入成功的jar包

连接数据库的驱动、协议、url
1 数据库:
MySQL
2 驱动类名:固定写法,每种数据库都有不同的驱动类名
com.mysql.jdbc.Driver

3 url格式:jdbc:mysql://协议 相当于https://或者http://
参数1:是否使用Unicode字符集 useUnicode=true
参数2:字符编码,也可以的GBK characterEncoding=utf-8
参数3:当数据库异常中断时是否自动连接 autoReconnect=true
参数4:一个请求默认执行多个sql(批量使用),默认是false allowMultiQueries=true
jdbc:mysql://数据库服务IP:端口/数据库名?参数1&参数2&参数3&参数4
datasource配置
resoures文件——application.properties文件中配置

//url
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/lesson2useUnicode=true&characterEncoding=utf-8&autoReconnect=true&allowMultiQueries=true
//数据库用户名
spring.datasource.username=root
//数据库登录密码
spring.datasource.password=123456
//驱动
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

mybatis的组成 一 数据库对象的映射类(就是实体类,写与数据库对应字段属性的类) 一般情况下,数据库有几张表,项目里就有几个映射类;数据库表有几个字段,映射类里就有几个属性

import lombok.Data;
@Data
public class InterfaceTest {
//定义主键时用Integer类型,不要用int类型,不然主键就变成了必查字段
private Integer interfaceId;
private String interfaceName;
private String interfaceType;
private String interfaceMethod;
private String interfaceAliasName;
}

数据库中有一张表,与该映射类的字段对应
在这里插入图片描述

二 mybatis的配置 1 在resources文件下的application.properties文件中配置

//写sql语句的.xml文件的地址,classpath是根目录,就是resources目录
mybatis.mapper-locations=classpath:/mymappers/*Mapper.xml
//扫描实体类的上层包,其实就是为了扫描跟数据库名称对应的实体类
mybatis.type-aliases-package=com.longteng.lesson2.my.mybatis
//打印日志,便于调试
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

三 对应的接口类

import org.apache.ibatis.annotations.Mapper;
/**
 * 在一个接口上添加@Mapper的注解,该接口就可以被mybatis识别
 * 这个类上加了@Mapper的注解,已经是个bean了,可以注入到其他类中
 * 写了@@Mapper就不用写@@Component.....这些注解了,一个意思
 */
@Mapper
public interface MyInterfaceTestMapper{
//创建一个新增的方法,入参是实体类
void addInterfaceTest(InterfaceTest interfaceTest);
}

四 Mapper的.xml文件(写sql语句的地方)

mybatis的sql全部写在xml文件里,真正执行的时候调用的mybatis的接口然后执行xml里的sql,关联的方式是xml里的namespace等于接口类的全称

<?xml version="1.0" encoding="UTF-8"?>
<!--使用mybatis的标签定义-->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace写入InterfaceTestMapper接口的绝对路径-->
<mapper namespace="com.longteng.lesson2.my.mybatis.InterfaceTestMapper">

</mapper>

以上就是数据库、mybatis的配置,现在就可以操作数据库了

1 新增数据到数据库

创建一个表单,用于提交接口,创建到数据库

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping(value = "/MyBatisController")
public class MyBatisController {
@RequestMapping("/InterfaceTestView")
public String addInterfaceTest() {
//返回的是一个.ftl文件
    return "/my/addInterfaceTest";
}
}

addInterfaceTest.ftl文件是一个表单

<form action="/MyBatisController/addInterface" method="post">
<table>
    <tr>
        <td>
            接口名称
            <input type="text" name="interfaceName" placeholder="请输入接口名称" required/>
        </td>
    </tr>
    <tr>
        <td>
            接口类型
            <input type="text" name="interfaceType" placeholder="请输入接口类型" required/>
        </td>
    </tr>
    <tr>
        <td>
            接口方法
            <select name="interfaceMethod">
                <option value="post">post</option>
                <option value="get">get</option>
        </td>
    </tr>
    <tr>
        <td>
            接口别名
            <input name="interfaceAliasName" placeholder="请输入接口别名" required/>
        </td>
    </tr>
    <tr>
        <td>
            <input type="reset" name="reset" value="重置">
            <input type="submit" name="submit" value="提交">
        </td>
    </tr>
</table>
</form>

请求 http://127.0.0.1:8080/MyBatisController/InterfaceTestView进入下图页面

在这里插入图片描述
编辑完成之后,点击提交,提交的是action="/MyBatisController/addInterface"的地址,就是下面的controller

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping(value = "/MyBatisController")
public class MyBatisController {
//注入接口,因为接口被@Mapper注解修饰,那么该接口也是一个bean
@Autowired
MyInterfaceTestMapper myInterfaceTestMapper;

@RequestMapping("/addInterface")
public String add(InterfaceTest interfaceTest) {
    try {
    //调用接口的addInterfaceTest方法
        myInterfaceTestMapper.addInterfaceTest(interfaceTest);
    } catch (Exception e) {
        e.printStackTrace();
    }
    //返回/my/success.ftl
    return "/my/success";
}
}

/my/success.ftl内容如下
在这里插入图片描述
interfaceTestMapper.xml文件里写入具体执行的sql,记住,要复制粘贴执行这段的时候一定要把注释全部都去掉才能执行成功

    <!--namespace写入InterfaceTestMapper接口的绝对路径-->
<mapper namespace="com.longteng.lesson2.my.mybatis.MyInterfaceTestMapper">
    <!--id就是接口中的方法名-->
    <insert id="addInterfaceTest"
    <!--需要返回一个主键,主键在数据库中是自增的-->
            useGeneratedKeys="true"
            <!--返回的该主键字段名称-->
            keyColumn="interface_test_id"
            <!--需要把这个主键字段赋值给哪个属性-->
            keyProperty="interfaceId"
            <!--方法的入参类型,就是属性类的全路径-->
            parameterType="com.longteng.lesson2.my.mybatis.InterfaceTest">
            <!--给哪个表插入数据,就写哪个表-->
            insert into interface_test
            <!--给哪些字段插入数据,就写哪些字段名-->
            (interface_name,interface_method,interface_type,interface_alias_name)
            <!--要插入的数据是对应的哪些字段,就是实体类里的字段,要与字段名的先后顺序一一对应,用#{}接收-->
            values (#{interfaceName},#{interfaceMethod},#{interfaceType},#{interfaceAliasName})
    </insert>
</mapper>

在表单页面编辑文本框提交,提交到
http://127.0.0.1:8080/MyBatisController/addInterface地址
在这里插入图片描述
数据库加入数据成功,如下图
在这里插入图片描述

2 从数据库删除数据

在interfaceTestMapper.xml中用标签定义删除

//id是接口中的删除方法的名称
    <delete id="deleteInterfaceTestById">
    //interface_test_id=#{0}的意思是接口方法的第一个参数,如果接口方法有多个参数
    //则用WHERE interface_test_id=#{0} AND interface_name=#{1}
    //接口方法中就是deleteInterfaceTestById(Integer id,String interfaceName);
            DELETE FROM interface_test WHERE interface_test_id=#{0}
    </delete>

接口中有个删除方法

void deleteInterfaceTestById(Integer id);

删除请求地址

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping(value = "/MyBatisController")
public class MyBatisController {
@Autowired
MyInterfaceTestMapper myInterfaceTestMapper;
@RequestMapping("del")
public String del(Integer id){
    myInterfaceTestMapper.deleteInterfaceTestById(id);
    return "/my/success";
}
}

浏览器请求
http://127.0.0.1:8080/MyBatisController/del?id=26
在这里插入图片描述
id为26的数据被删除
在这里插入图片描述

删除 若interfaceTestMapper.xml文件中用的#{0}、#{1}那么接口类的方法请求地址里的参数用基础类型加String类型,上述删除例子 若interfaceTestMapper.xml文件中用的#{interfaceId}接收参数,那么接口类中的方法参数用对象类型,浏览器的请求参数也用对象属性,如下例子

//interfaceTestMapper.xml文件中
        <delete id="deleteInterfaceTestById">
            DELETE FROM interface_test WHERE interface_test_id=#{interfaceId}
    </delete>


//接口中的方法
	    void deleteInterfaceTestById(InterfaceTest interfaceTest);

//controller中入参要用对象类型
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping(value = "/MyBatisController")
public class MyBatisController {
@Autowired
MyInterfaceTestMapper myInterfaceTestMapper;

@RequestMapping("del")
public Object del(InterfaceTest interfaceTest) {
    myInterfaceTestMapper.deleteInterfaceTestById(interfaceTest);
    return "/my/success";
}
}

请求路径中参数用对象属性
http://127.0.0.1:8080/MyBatisController/del?interfaceId=27

删除成功
在这里插入图片描述

3 修改数据库中已有数据

接口中的方法

void update(InterfaceTest interfaceTest);

interfaceTestMapper.xml的update sql,update条件是id,数据库字段要与实体类的属性一一对应

        <update id="update" parameterType="com.longteng.lesson2.my.mybatis.InterfaceTest">
            UPDATE interface_test
            SET interface_type=#{interfaceType},
            interface_name=#{interfaceName},
            interface_method=#{interfaceMethod},
            interface_alias_name=#{interfaceAliasName}
            WHERE interface_test_id=#{interfaceId}
    </update>

更改的controller,进入update页

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping(value = "/MyBatisController")
public class MyBatisController {
@Autowired
MyInterfaceTestMapper myInterfaceTestMapper;
@RequestMapping("/updateInterfaceTestView")
public String updateInterfaceTest() {
    return "/my/updateInterfaceTest";
}
}

请求http://127.0.0.1:8080/MyBatisController/updateInterfaceTestView进入下面页面,跟据数据库已有的数据id更改
在这里插入图片描述
上图提交后进入地址:http://127.0.0.1:8080/MyBatisController/update
如下图
在这里插入图片描述
数据库更改前
在这里插入图片描述
数据库更改后
在这里插入图片描述

上述的update有个bug,就是前端一共4个字段,但是只想修改一个字段,其他字段不修改的时候,没有修改的字段因为是不填写状态,就在数据库表中变成了空,所以要用动态修改来解决这个问题

意思就是前端页面传值了(属性不等于null)就将传的值赋值给对应的该字段,若不传值,就不赋值,用旧数据

只需要将interfaceTestMapper.xml改为如下

    <update id="update" parameterType="com.longteng.lesson2.my.mybatis.InterfaceTest">
            UPDATE interface_test
            <set>
                    <if test="null!=interfaceType">
                            interface_type=#{interfaceType},
                    </if>
                    <if test="null!=interfaceName">
                            interface_name=#{interfaceName},
                    </if>
                    <if test="null!=interfaceMethod">
                            interface_method=#{interfaceMethod},
                    </if>
                    <if test="null!=interfaceAliasName">
                            interface_alias_name=#{interfaceAliasName},
                    </if>
            </set>
            WHERE interface_test_id=#{interfaceId}
    </update>

注意1:每个if中的set赋值都要有逗号,哪怕是最后一个也要有逗号
注意2:if中表达式的判断是用类属性判断,若前端请求不传值,就展示原本值,不是用数据库字段名判断
注意3:if中的判断一定要用 null!=属性名 不能用 属性名!=null,要不然根本没效果,该空的字段还是空

4 查询

interfaceTestMapper.xml文件的查询语句,要复制这段执行的话把注释去掉

    <!--返回的数据类型用resultType类型接收-->
    <select id="select" parameterType="com.longteng.lesson2.my.mybatis.InterfaceTest"
                        resultType="com.longteng.lesson2.my.mybatis.InterfaceTest">
            --查询用别名,接收的是属性名,就给每个字段起个属性名
            SELECT interface_type as interfaceType,
                    interface_name as interfaceName,
                    interface_method as interfaceMethod,
                    interface_alias_name as interfaceAliasName
            FROM interface_test
            WHERE interface_test_id=#{interfaceId}
    </select>

接口方法:因为查询后有返回结果,所以接口方法用InterfaceTest 返回类型

InterfaceTest select(InterfaceTest interfaceTest);

请求的controller

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping(value = "/MyBatisController")
public class MyBatisController {
@Autowired
MyInterfaceTestMapper myInterfaceTestMapper;
@RequestMapping("/select1")
public @ResponseBody Object select(InterfaceTest interfaceTest){
    return myInterfaceTestMapper.select(interfaceTest);
}
}

因为返回的是一个json串所以用@ResponseBody

请求
http://127.0.0.1:8080/MyBatisController/select1?interfaceId=28
在这里插入图片描述

这样只能返回一条结果,要返回多条结果需要优化 查询返回多条结果

1 interfaceTestMapper.xml文件中去掉参数类型(因为不用传参就不需要参数类型了)、where条件(因为要查询的是所有数据,所以不用where条件)

        <select id="select2" resultType="com.longteng.lesson2.my.mybatis.InterfaceTest">
            SELECT interface_type as interfaceType,
                    interface_name as interfaceName,
                    interface_method as interfaceMethod,
                    interface_alias_name as interfaceAliasName
            FROM interface_test
    </select>

2 接口中的方法也去掉传参,因为返回的是多条结果,用List接收(只要查询结果的个数是多少不确定的情况下都用List接收)

    List<InterfaceTest> select2();

3 controller中的方法也去掉入参

    @RequestMapping("/select2")
public @ResponseBody Object select2(){
    return myInterfaceTestMapper.select2();
}

请求 http://127.0.0.1:8080/MyBatisController/select2 返回数据库表中所有内容
在这里插入图片描述

5 多条件条件动态查询

上述两个例子
例子1只能返回一条结果
例子2必须返回全部结果
若是要特定查询怎么办?

1 interfaceTestMapper.xml文件中将where条件动态定义,与update中的区别是,每个if去掉逗号、加上and,入参类型是属性类的绝对地址,where条件也是可以加上主键id的,不一定非要全写,用多少写多少

       <select id="select2"
            parameterType="com.longteng.lesson2.my.mybatis.InterfaceTest"
            resultType="com.longteng.lesson2.my.mybatis.InterfaceTest">
            SELECT interface_type as interfaceType,
                    interface_name as interfaceName,
                    interface_method as interfaceMethod,
                    interface_alias_name as interfaceAliasName
            FROM interface_test
            //1=1没有什么意思,就是占位符,能让后面接上and,因为不能确定是第几个参数为空
            WHERE 1=1
            <if test="null!=interfaceType">
                    AND interface_type=#{interfaceType}
            </if>
            <if test="null!=interfaceName">
                    AND interface_name=#{interfaceName}
            </if>
            <if test="null!=interfaceMethod">
                    AND interface_method=#{interfaceMethod}
            </if>
            <if test="null!=interfaceAliasName">
                    AND interface_alias_name=#{interfaceAliasName}
            </if>
    </select>

2 接口你方法中,入参类型是属性类行,返回用List

List<InterfaceTest> select2(InterfaceTest interfaceTest);

3 controller中入参类型也是属性类的类型

    @RequestMapping("/select2")
public @ResponseBody Object select2(InterfaceTest interfaceTest){
    return myInterfaceTestMapper.select2(interfaceTest);
}

这样查询的入参(就是查询的where条件)就能用随意用,或者用多条
例:以interfaceType为条件查询
http://127.0.0.1:8080/MyBatisController/select2?interfaceType=https
例:以interfaceType和interfaceAliasName多条件查询
http://127.0.0.1:8080/MyBatisController/select2?interfaceType=https&interfaceAliasName=bbb接口

6 resultMap

以上查询都是用别名的方式映射,resultType是返回类型,现在可以将resultType换成resultMap
好处1:减少重复代码
好处2:多表联合查询时只能用resultMap
例子,定义一个resultMap
1 interfaceTestMapper.xml文件中增加resultMap

    <!--用resultMap标签,id的value就是一个名字而已,-->
    <!--type的value就是要返回的类型,就是属性类的绝对路径-->
    <resultMap id="interfaceMap" type="com.longteng.lesson2.my.mybatis.InterfaceTest">
            <!--只有主键是用id标签,其他字段都是result标签-->
            <!--column是数据库的字段名,property是类对应的属性名-->
            <id column="interface_test_id" property="interfaceId"></id>
            <result column="interface_type" property="interfaceType"></result>
            <result column="interface_name" property="interfaceName"></result>
            <result column="interface_method" property="interfaceMethod"></result>
            <result column="interface_alias_name" property="interfaceAliasName"></result>
    </resultMap>

2 interfaceTestMapper.xml文件中的查询改造,要复制执行需要删除掉注释

        <select id="select2"
            parameterType="com.longteng.lesson2.my.mybatis.InterfaceTest"
            <!--返回类型用resultMap的key,value就是resultMap的名称-->
            resultMap="interfaceMap">
            <!--查询不用再写字段名映射属性名了,直接用属性名或者全表扫描-->
            SELECT *
            FROM interface_test
            WHERE 1=1
            <if test="null!=interfaceType">
                    AND interface_type=#{interfaceType}
            </if>
            <if test="null!=interfaceName">
                    AND interface_name=#{interfaceName}
            </if>
            <if test="null!=interfaceMethod">
                    AND interface_method=#{interfaceMethod}
            </if>
            <if test="null!=interfaceAliasName">
                    AND interface_alias_name=#{interfaceAliasName}
            </if>
    </select>

这样与例子5的查询使用、查询结果都是一样的

7 模糊查询

要使用like的时候需要对sql进行拼接 用MySQL的关键字CONCAT

Where interface_name like CONCAT('%',#{},'%')

例:

    <select id="select2"
            parameterType="com.longteng.lesson2.my.mybatis.InterfaceTest"
            resultMap="interfaceMap">
            SELECT *
            FROM interface_test
            WHERE 1=1
            <if test="null!=interfaceType">
                    AND interface_type LIKE concat ('%',#{interfaceType},'%')
            </if>
            <if test="null!=interfaceName">
                    AND interface_name LIKE concat ('%',#{interfaceName},'%')
            </if>
            <if test="null!=interfaceMethod">
                    AND interface_method LIKE concat ('%',#{interfaceMethod},'%')
            </if>
            <if test="null!=interfaceAliasName">
                    AND interface_alias_name LIKE concat ('%',#{interfaceAliasName},'%')
            </if>
    </select>

数据库数据
在这里插入图片描述
查询接口别名有百度两个字的
http://127.0.0.1:8080/MyBatisController/select2?interfaceAliasName=百度

查询结果
在这里插入图片描述

8 子对象集合

子对象集合必须用resultMap
子对象集合一般用于多表联合查询,然后有父子关系
创建一个实体类TestCase

import lombok.Data;
@Data
public class TestCase {
private Integer testCaseId;
private String testCaseName;
//该字段关联InterfaceTest类的interfaceId字段
private Integer interfaceId;
}

创建一张表与test_case与TestCase 类一一对应(字段与属性一一对应)
在这里插入图片描述
InterfaceTest类增加一个TestCase 类型的属性

private List<TestCase> testCaseList;

给test_case表增加两条数据,绑定到一个接口id上
xml文件中写新增sql

        <insert id="addTestCase"
            useGeneratedKeys="true"
            keyColumn="test_case_id"
            keyProperty="testCaseId"
            parameterType="com.longteng.lesson2.my.mybatis.TestCase">
            insert into test_case
            (test_case_name,interface_id)
            values (#{testCaseName},#{interfaceId})
    </insert>

接口中新增一个方法

    void addTestCase(TestCase testCase);

controller中

    @RequestMapping("addTestCase")
public @ResponseBody String addTestCase(TestCase testCase){
    myInterfaceTestMapper.addTestCase(testCase);
    return testCase.getTestCaseName();
}

新增成功如下图
两条数据都绑定到了接口id为28的接口上
在这里插入图片描述

现在有一个需求,查询一个接口绑定了几条测试用例

方式一:关联查询:耦合度很高,不建议使用,可以使用下一个低耦合的办法

在接口类中增加一个方法

//因为不知道返回的结果是几条数据,用List作为返回类型,入参是String类型,因为sql的查询条件是用接口别名作为查询条件
List<InterfaceTest> getInterfaceAndCase(String interfaceAliasName);

将子表test_case也作为一个resultMap

//type的value是子表(测试用例表)的绝对路径
        <resultMap id="testCase" type="com.longteng.lesson2.my.mybatis.TestCase">
       //主键用id标签,其他字段用result标签,column是数据库字段名,property是属性名
            <id column="test_case_id" property="testCaseId"></id>
            <result column="test_case_name" property="testCaseName"></result>
            <result column="interface_id" property="interfaceId"></result>
    </resultMap>

主表的resultMap中药加上子表的映射

//collection 是作为引入resultMap的,property的value是主表最新添加的属性名(就是子表类型的属性名),resultMap的value是子表的resultMap的id,就是子表的resultMap名称
<collection property="testCaseList" resultMap="testCase">

interfaceTestMapper.xml中的sql语句写

//id就是接口中的方法名,resultMap写主表的resultMap名称
<select id="getInterfaceAndCase" resultMap="interfaceMap">
//记录接口的interface_test为主表,记录测试用例的test_case为子表
            SELECT it.*,tc.* FROM interface_test it
            LEFT JOIN test_case tc
            ON it.interface_test_id=tc.interface_id
            //where条件用接口别名,因为接口中的查询方法只有一个参数(多个的时候,第一个也一样)用#{0}
            WHERE interface_alias_name=#{0}
    </select>

controller中

    @RequestMapping("/selectInterfaceAndCase")
public @ResponseBody Object selectInterfaceAndCase(String name){
    return myInterfaceTestMapper.getInterfaceAndCase(name);
}

请求地址
http://127.0.0.1:8080/MyBatisController/selectInterfaceAndCase?name=百度接口协议
返回接口名称与对应的2个测试用例
在这里插入图片描述

方式二,子查询:低耦合

该方法中每个查询相对独立,并且查询的复用性也强
interfaceTestMapper.xml文件中
针对子表的resultMap

//resultMap的名称,类型:子表类型的绝对路径
    <resultMap id="testCase" type="com.longteng.lesson2.my.mybatis.TestCase">
    //主键用id,其他字段用result;column数据库字段名,property类属性名
            <id column="test_case_id" property="testCaseId"></id>
            <result column="test_case_name" property="testCaseName"></result>
            <result column="interface_id" property="interfaceId"></result>
    </resultMap>

针对子表的查询语句,子表的查询id也可以对应到一个接口的查询方法上,也是一个单独的查询

//id是该查询的名称,resultMap的值是子表的resultMap名称
    <select id="getTestCase" resultMap="testCase">
            SELECT * FROM test_case
            <where> 1=1
                    <if test="null!=testCaseId">
                            AND test_case_id=#{testCaseId}
                    </if>
                    <if test="null!=testCaseName">
                            AND test_case_name=#{testCaseName}
                    </if>
                    <if test="null!=interface_id">
                            AND interface_id=#{interfaceId}
                    </if>
            </where>
    </select>

针对主表的查询语句

	//id是接口中的查询方法名
        <select id="select2"
        //入参类型:主表对应类的绝对路径
            parameterType="com.longteng.lesson2.my.mybatis.InterfaceTest"
            //返回的类型,resultMap的值是主表resultMap的名称
            resultMap="interfaceMap">
            SELECT *
            FROM interface_test
            WHERE 1=1
            <if test="null!=interfaceType">
                    AND interface_type LIKE concat ('%',#{interfaceType},'%')
            </if>
            <if test="null!=interfaceName">
                    AND interface_name LIKE concat ('%',#{interfaceName},'%')
            </if>
            <if test="null!=interfaceMethod">
                    AND interface_method LIKE concat ('%',#{interfaceMethod},'%')
            </if>
            <if test="null!=interfaceAliasName">
                    AND interface_alias_name LIKE concat ('%',#{interfaceAliasName},'%')
            </if>
    </select>

针对主表的resultMap

    <!--用resultMap标签,id的value就是一个名字而已,-->
    <!--type的value就是要返回的类型,就是属性类的绝对路径-->
    <resultMap id="interfaceMap" type="com.longteng.lesson2.my.mybatis.InterfaceTest">
            <!--只有主键是用id标签,其他字段都是result标签-->
            <!--column是数据库的字段名,property是类对应的属性名-->
            <id column="interface_test_id" property="interfaceId"></id>
            <result column="interface_type" property="interfaceType"></result>
            <result column="interface_name" property="interfaceName"></result>
            <result column="interface_method" property="interfaceMethod"></result>
            <result column="interface_alias_name" property="interfaceAliasName"></result>
            //引入子查询用collection;property的值是子表类在主表中对应的属性名称
            <collection property="testCaseList"
            //select的值对应该文件中子表的查询语句的名称
                        select="getTestCase"
             //子表中,interfaceId:关联主表的属性名,interface_test_id主表的主键字段名
             //就是用主表的主键名映射,就是将主表的查询结果映射到子表对应主表主键关联的那个字段对应的属性上继续查询子表,因为主表的主键与子表的interface_id对应,相对的属性也就是一一对应的
                        column="{interfaceId=interface_test_id}">
            </collection>
    </resultMap>

接口中的方法

//因为返回的不知道是多少条数据,所以用List,该方法名被主表的查询id使用
List<InterfaceTest> select2(InterfaceTest interfaceTest);

controller中

@RequestMapping("/select2")
public @ResponseBody Object select2(InterfaceTest interfaceTest){
    return myInterfaceTestMapper.select2(interfaceTest);
}

请求地址就很灵活了,不管是全部查出映射,还是加上任意或者组合条件均可查询
例:
查询出主表接口别名为“百度接口协议”的接口有几条测试用例
在这里插入图片描述

查询全部接口对应测试用例表有几条数据
在这里插入图片描述

上面的例子是一个接口对应多个测试用例的情况,这是一对多的情况,那要是一对一呢?
将主表中的collection 关键字改为association,将主表中的属性改为对象,不用List即可

sql标签的应用,主要是为了抽取共性的内容,让代码不冗余,轻松愉快
例如查询条件where很多都是一样的那就可以用sql抽取

sql将where条件封装,id就是该sql的名称
        <sql id="testCase_where_list">
            <where>
                    1=1
                    <if test="null!=testCaseId">
                            AND test_case_id=#{testCaseId}
                    </if>
                    <if test="null!=testCaseName">
                            AND test_case_name=#{testCaseName}
                    </if>
                    <if test="null!=interface_id">
                            AND interface_id=#{interfaceId}
                    </if>
            </where>
    </sql>

同理:查询条件用*很影响性能,多个查询语句的查询字段要是相同的话也可以用sql封装,用as是因为,查询的时候用的是属性名查询的,有找不到查询字段名的时候,所以要起别名

    <sql id="select_list">
    test_case_id as testCaseId,test_case_name as testCaseName,interface_id as interfaceId
    </sql>

那么查询语句用

        <select id="getTestCase" resultMap="testCase">
        //include的值就是查询条件sql的封装的名称
        SELECT <include refid="select_list"></include>
        FROM test_case
        //include 的值是where条件的封装的值
        <include refid="testCase_where_list"></include>
    	</select>

对于一些不能重复的值就要先将数据库该不能重复的字段设置为unique(如下图)

这样即使程序业务中没有做判断也不会加入重复的值进入数据库
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41767337/article/details/89362141
今日推荐