Mybatis(进阶部分)

news2024/11/17 11:35:57

四 Mybatis完成CURD(二)

4.5 多条件CRUD

        之前的案例中,接口里方法的形参个数都是1个;如果方法形参是两个或者两个以上时,MyBatis又该如何获取获取参数呢?

Mybatis提供了好几种方式,可以获取多个参数的值

第一种: 使用arg0,arg1…或者param1,param2…来按照参数顺序获取对应的值

 /*
        通过部门编号,领导编号,员工姓名,查询员工信息
     */
    Employee findByDeptnoAndMgrAndEname(int deptno, int mgr, String ename);

        接口里的方法与Sql映射文件中的语句进行映射后,并且在调用方法期间,Mybatis会默认将所有传入到方法中的实际参数封装到一个Map对象中,实际参数作为value,按照从左到右的顺序,分别绑定到key名为arg0,arg1…或者param1,param2…上。

因此我们在获取参数时,可以这样写

    <!--Employee findByDeptnoAndMgrAndEname(int deptno, int mgr, String ename);-->
<!--    方法的参数有多个时,可以不用子标签里书写parameterType属性-->
<!--    没有指定参数类型时,会默认从自动封装的Map对象中,寻找具体的值给?赋上
        使用arg0,arg1,arg2...
        或者使用param1,param2,param3...
-->
    <select id="findByDeptnoAndMgrAndEname" resultType="employee" resultMap="resultMap1" >
<!--        select * from emp where deptno = #{arg0} and mgr =#{param2} and ename=#{arg2}-->
<!--        select * from emp where deptno = #{arg0} and mgr =#{arg1} and ename=#{arg2}-->
        select * from emp where deptno = #{param1} and mgr =#{param2} and ename=#{param3}

    </select>

测试:

@Test
    public void test1(){
        //获取代理对象
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        /*
            当对应的Sql映射文件中,没有指定参数类型时,Mybatis会将实际参数封装到一个Map对象中
                arg0,arg1...作为key,
                实际参数从左到右依次作为value与key对应。
                还会再存储一组键值对:
                param1,param2....作为key
                实际参数从左到右依次作为value与key对应。
         */
        Employee scott = mapper.findByDeptnoAndMgrAndEname(30, 7698, "TURNER");
        System.out.println(scott);
    }

第二种:Map作为参数

map 集合:只需要保证 SQL 中的参数名和 map 集合的键的名称对应上,即可设置成功

/*
        如果在设计方法时,需要使用多个形参。为了将值传入到Mybatis的映射文件中的sql语句中,我们可以换一个思路:
        就是在设计方法时,形参设计成Map类型,在调用时,将各种实际参数封装到Map对象中,然后只需要传入Map参数即可

        注意,映射文件中,要使用parameterType:来指定形参为Map类型,map/Map
     */
    Employee findByMap(Map<String,Object> map);

映射文件:

<!--    Employee findByMap(Map<String,Object> map);-->
<!--    如果形参是Map类型,占位符中的名称必须是map的key,所以在封装成map对象时,尽量见名知意-->
    <select id="findByMap" resultType="Employee" resultMap="resultMap1" parameterType="map">
        select * from emp where deptno = #{deptno} and mgr = #{mgr} and empno = #{empno} and job = #{job}
    </select>

测试:

 @Test
    public void test2(){
        //获取代理对象
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        // 自定义一个map类型,用于封装浏览器传过来的各种值。
        Map<String,Object> map = new HashMap<>();
        map.put("deptno",30);
        map.put("mgr",7698);
        map.put("empno",7499);
        map.put("job","SALESMAN");
        //map在存储键值对时,key必须和占位符中的名字一样。因为占位符是通过key来从map中获取具体的value值,给?赋值。
        Employee byMap = mapper.findByMap(map);
        System.out.println(byMap);
    }

第三种:实体类作为参数

实体类封装参数:只需要保证 SQL 中的参数名和实体类属性名对应上,即可设置成功

实体类:

package com.mybatis.pojo;

public class ParamsType {
    private Integer empno;
    private String ename;
    private String job;
    private Integer mgr;

    public ParamsType() {}

    public ParamsType(Integer empno, String ename, String job, Integer mgr) {
        this.empno = empno;
        this.ename = ename;
        this.job = job;
        this.mgr = mgr;
    }

    @Override
    public String toString() {
        return "ParamsType{" +
                "empno=" + empno +
                ", ename='" + ename + '\'' +
                ", job='" + job + '\'' +
                ", mgr=" + mgr +
                '}';
    }
}

接口:

/*
        如果在设计方法时,需要使用多个形参。除了使用Map类型外,还可以将这多个形参设计到一个实体类对象上。
        比如: 如果这些形参都是表对应的那个实体类,那就可以直接使用表对应的实体类,比如Employee
            还可以单独封装到一个参数实体类,专门用于传参用的,比如定义一个类型ParamsType。
        select * from emp where empno = ? and ename = ? and job = ? and mgr = ?

     */
    Employee findByEntity(ParamsType params);

 映射文件:

<!--     Employee findByEntity(ParamsType params);-->
    <select id="findByEntity" resultType="Employee" resultMap="resultMap1" parameterType="paramsType">
        select * from emp where empno=#{empno} and ename=#{ename} and job=#{job} and mgr=#{mgr}
    </select>

 测试代码

    @Test
    public void test3(){
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        ParamsType paramsType = new ParamsType(7499,"ALLEN","SALESMAN",7698);
        Employee byEntity = mapper.findByEntity(paramsType);
        System.out.println(byEntity);
    }

第四种:使用@Param注解命名参数

散装参数:需要使用 @Param (" SQL 中的参数占位符名称")

    /*
        如果在设计方法时,需要使用多个形参。除了上述方法之外,还可以使用注解@Param("占位符的名字")。
        这种方式就可以使用对应的形参给对应的占位符赋值了。非常方便。
     */
    Employee findByAnnotation(@Param("empno") int empno,
                              @Param("ename") String ename,
                              @Param("job") String jobb,
                              @Param("mgr") int mgrno);

 映射文件:

<!--    Employee findByAnnotation(@Param("empno") int empno,
                              @Param("ename") String ename,
                              @Param("job") String jobb,
                              @Param("mgr") int mgrno);-->
    <select id="findByAnnotation" resultType="Employee" resultMap="resultMap1">
        select * from emp where empno=#{empno} and ename=#{ename} and job=#{job} and mgr=#{mgr}

    </select>

测试类:

    @Test
    public void test4(){
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        Employee byEntity = mapper.findByAnnotation(7499,"ALLEN","SALESMAN",7698);
        System.out.println(byEntity);
    }

4.6 动态SQL

        SQL语句会随着用户的输入和外部条件的变化而变化,我们称之为动态SQL。MyBatis对动态SQL有很强大的支持。

4.6.1 where/if标签

        if标签,是根据Test属性中的布尔表达式的值,从而决定是否执行包含在其中的SQL片段。如果判断结果为true,则执行其中的SQL片段;如果结果为false,则不执行其中的SQL片段

应用场景如图所示: 

存在的问题:第一个条件不需要逻辑运算符。  

案例演示:

在接口EmployeeMapper.java里添加如下方法

 /* ---where条件可能会随着用户的输入而改变的我们称之为动态sql----
        mybatis支持动态sql的写法
        第一个动态SQL: 应用场景: 浏览器在查询操作时,从多个条件中进行任意个组合条件进行查询,条件个数未知
    * */
    Employee findByConditionNum(Map<String,Object> map);

在映射文件EmployeeMapper.xml里配置如下

第一种方案:使用恒等式让所有条件格式都一样

<!--    动态sql的练习
    Employee findByConditionNum(Map<String,Object> map);
    用户有的时候,按照 员工编号查询....
        有的时候按照 员工姓名查询....
        有的时候按照 员工编号 和职位查询
        select * from emp where empno = ?
        select * from emp where ename = ?
        select * from emp where empno = ? and job = ?
-->
<!--    第一种写法:使用1=1恒成立的写法,来解决 可能多一个and关键字的问题
-->
    <select id="findByConditionNum" resultType="Employee" resultMap="resultMap1" parameterType="map">
        select * from emp
        where 1=1
        <if test="empno != null and empno!='' ">
            and empno = #{empno}
        </if>
        <if test="ename != null and ename!='' ">
            and ename = #{ename}
        </if>
        <if test="job != null and ename!='' ">
            and job = #{job}
        </if>

    </select>

 第二种方案:使用<where>标签替换where关键字。 注意:where标签会将第一个条件之前的连接符自动去掉

    
<-- 第二种写法:配合where标签, where标签的作用,用来连接条件,如果在第一个条件前有多余连接符号(and 、or)。会自动去掉 -->
        <select id="findByConditionNum" resultType="Employee" resultMap="resultMap1" parameterType="map">  
        select * from emp
        <where>
            <if test="empno!=null and empno!='' ">
                empno = #{empno}
            </if>
            <if test="ename!=null and ename!='' ">
                and ename = #{ename}
            </if>
            <if test="job!=null and job!='' ">
                and job = #{job}
            </if>
        </where>
    </select>

4.6.2 choose/when标签  

应用场景:

        choose(when,otherwise):类似于java的switch-case-default, 只要满足一个when,choose就结束了,如果都不满足,就会执行otherwise。

1)在接口EmployeeMapper里添加如下方法

/*
        第二个动态sql:  应用场景: 浏览器在查询操作时,只能从多个条件中选择一个条件进行查询。条件个数只有一个
     */
    Employee findByConditionOne(Map<String,Object> map);

2)在sql映射文件EmployeeMapper.xml里添加如下内容  

<!--    Employee findByConditionOne(Map<String,Object> map);-->
<!--    对应的标签:  choose-when-otherwise  与java的switch-case(break)-default功能一样,只能执行其中一个分支
                choose是父标签
                when是子标签,可以有多个,如果执行了某一个when,则结束choose
                otherwise是子标签,只能有一个,如果没有执行的when,则执行otherwise

    需求: 用户可能按照员工编号查询,也可能按照员工姓名查询,也可能按照奖金查询。
-->

    <select id="findByConditionOne" resultType="Employee" resultMap="resultMap1" parameterType="map">
        select * from emp where
        <choose>
            <when test="empno!=null and empno!='' ">
                empno = #{empno}
            </when>
            <when test="ename!=null and ename!='' ">
                ename = #{ename}
            </when>
            <when test="comm!=null and comm!='' ">
                comm = #{comm}
            </when>
            <otherwise>
                1=1
            </otherwise>
        </choose>
    </select>

 3)测试

 /*模拟场景浏览器端只传过来一个条件进行查询*/
    @Test
    public void test6(){
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        Map<String,Object> map = new HashMap<>();
        map.put("comm",1400);
        Employee byConditionOne = mapper.findByConditionOne(map);
        System.out.println(byConditionOne);
    }

4.6.3 set/if标签

        当进行修改时,有些字段可能有选择的进行修改,这时我们就可以使用<set>标签 配合<if>标签来完成操作。set标签会自动将最后一个条件的逗号去掉。

 1)在接口EmployeeMapper里添加如下方法

/*
        第三个动态sql: 应用场景: 浏览器在修改信息时,修改的文本框的个数不定
     */
    void updateByCondition(Map<String,Object> map);

2)在sql映射文件EmployeeMapper.xml里添加如下内容  

<!--      void updateByCondition(Map<String,Object> map);

        标签:
            set/if两个标签的应用
            Set标签可以自动去掉最后一个字段后面的逗号。

        应用场景:  浏览器在修改信息时,可能修改了员工姓名,职位
                  也可能修改了员工的工资和奖金,总之就是修改的内容不一定是什么。
-->
    <update id="updateByCondition" parameterType="map">
        update emps
        <set>
            <if test="ename != null and ename != '' ">
                ename = #{ename},
            </if>
            <if test="job != null and job != '' ">
                job = #{job},
            </if>
            <if test="mgr != null and mgr>0">
                mgr = #{mgr},
            </if>
            <if test="hiredate != null and hiredate !='' ">
                hiredate = #{hiredate},
            </if>
            <if test="sal != null and sal >0">
                sal = #{sal},
            </if>
            <if test="comm != null and comm>=0">
                comm = #{comm},
            </if>
            <if test="deptId != null and deptId >0">
                deptno = #{deptId},
            </if>
        </set>
        where empno = #{empno}

    </update>

 3)测试

/*
        浏览器传过来的要修改的字段不一定是哪些
     */
    @Test
    public void test7(){
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        Map<String,Object> map = new HashMap<>();
        map.put("empno",7499);
        map.put("ename","TOM");
        map.put("job","ClEAR");
        map.put("sal",1500);
        mapper.updateByCondition(map);
        sqlSession.commit();
    }

4.6.4 foreach标签

<foreach>标签的使用, 比如进行集合查询等操作

1)在接口EmployeeMapper里添加如下方法

两种写法:直接传入字符串(使用${})和封装到集合中(foreach方法)

/*
            第四个动态sql:
            应用场景: 浏览器端可能使用了复选框来勾选要查询的某一个字段的多个值的数据,底层sql应该是一个集合查询
            比如:
            select * from emp where job in ('SALESMAN','ANALYST')
            传过来的某一个字段值不一定有几个
            select * from emp where ename in('tom','lily','lucy')

            empnos: "'tom','lily','lucy'"
     */
    List<Employee> findByOneColumnMuitlValue1(String empnos);
    /* foreach标签的应用:
            对一个集合进行遍历。

     */
    List<Employee> findByOneColumnMuitlValue2(@Param("enames") List<String> enames);

2)在EmployeeMapper.xml里添加如下内容

<!--    List<Employee> findByOneColumnMuitlValue1(String empnos);

        一个字段的多个值的查询操作:  一种变相的写法。
-->
    <select id="findByOneColumnMuitlValue1" resultType="Employee" parameterType="string" resultMap="resultMap1">
        select * from emp where empno in (${empnos})
    </select>
<!--    List<Employee> findByOneColumnMuitlValue2(List<String> enames);

        foreach标签: 用于遍历集合参数的。  通常用于(not) in 这种sql语句。
        属性:
            -collection: 用于指定方法的形参
            -open :  指定集合的开始符号,比如"("
            -close :  指定集合的结束符号,比如")"
            -item: 遍历期间的元素的存储位置,即变量   注意: foreach标签中要使用变量
            -separator: 分隔符,比如","
-->
    <select id="findByOneColumnMuitlValue2" resultType="Employee" resultMap="resultMap1">
        select * from emp
        where ename in
        <foreach collection="enames" open="(" close=")" item="ename" separator="," >
            #{ename}
        </foreach>
    </select>

3)测试

    @Test
    public void test8(){
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        String empnos = "7499,7521,7566";
//        String enames = "'TOM','WARD'";
        List<Employee> emps = mapper.findByOneColumnMuitlValue1(empnos);
        emps.forEach(System.out::println);
    }

    @Test
    public void test9(){
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
        List<String> names = new ArrayList<>();
        names.add("TOM");
        names.add("WARD");
        names.add("KING");
        List<Employee> list = mapper.findByOneColumnMuitlValue2(names);
        list.forEach(System.out::println);
    }

4.7 不同返回值类型的查询

4.7.1 返回基本数据类型

/*
        查询student表中的记录个数
     */
    int selectCount();
    /*
<select id="selectCount" resultType="_int">
        select count(*) from student
    </select>

4.7.2 返回引用类型(实体类)

/*
        返回值为实体类的
     */

    Student findById(Integer id);
<!--    Student findById(Integer id);
        属性resultType: 书写方法的返回值类型  代理对象通过sql语句进行查询,然后将查询到的结果自动封装成返回值类型的实例-->
    <select id="findById" resultType="Student">
        select * from student where id=#{arg0022331kkkskk}
    </select>

4.7.3 返回List类型

 /*
        返回值为List类型
     */
    List<Student> findByPage(@Param("offset") int offset,@Param("pageSize") int pageSize);
<!--    List<Student> findByPage(@Param("page") int page,@Param("pageSize") int pageSize);
        返回值类型: 如果方法的返回值类型时List, 那么在属性resultType上只需要指定集合当元素类型的名字即可
    -->
    <select id="findByPage" resultType="Student">
        select * from student limit #{offset},#{pageSize}
    </select>

4.7.4 返回Map类型

/*
        返回值为Map类型
        应用场景: 将查询出来的信息封装成Map形式的样子。
            表的字段名作为key
            字段值作为value
     */
    Map<String,Object> findByName(String name);
<select id="findByName" resultType="Map">
        select * from student where name=#{name}
    </select>

4.7.5 返回Map实例的集合

 /*
    应用场景: 将查询出来的多条记录,封装到Map集合中

    条件:通过性别,开头查询出来多条记录, 封装到List集合中,泛型为Map
     */
    List<Map<String,Object>> findByGender(@Param("gender") String gender);
<select id="findByGender" resultType="Map">
        select * from student where gender=#{gender}
    </select>

4.7.6 返回Map的另一种情况

    /**
     * 1001  => {address=江南, gender=m, name=刘备, age=40, sid=1001}
     * 1002  => {address=上海, gender=m, name=关羽, age=35, sid=1002}
     * 1003  => {address=长春, gender=m, name=赵云, age=27, sid=1004}
     */
//    Map<String,Map<String,Object>>
    @MapKey("id")
    Map<Integer,Object> findByGender2(@Param("gender") String gender);
    <select id="findByGender2" resultType="Map">
        select * from student where gender=#{gender}
    </select>

4.7.7 返回Set集合

/*
    * 应用场景:  数据库里的记录可能有重复数据,  然后再进行查询时,想要进行去重操作,我们就可以设计方法的
    * 返回值为Set,  泛型为该表的实体类   注意:  实体类必须重写equals方法和hashCode方法。
    * */
Set<Student> findAllByDistinct();
<select id="findAllByDistinct" resultType="student">
   select * from student
</select>

4.8 特殊SQL的查询

4.8.1 模糊查询

在sql映射文件中的三种写法:

like  '%${username}%'
like concat('%',#{username},'%')
like "%"#{username}"%"

案例演示:

/*
        模糊查询:select * from student where name like '%备%'
     */
    List<Student> findByNameLike(@Param("shortName") String shortName);
<!--    select * from student where name like '%${shortName}%'-->
<!--    select * from student where name like concat('%',#{shortName},"%")-->

<!--    模糊匹配。-->
    <select id="findByNameLike" resultType="Student">
         select * from student where name like "%"#{shortName}"%"
    </select>

4.8.2 批量删除

两种方法:

        批量删除: 一般都是通过唯一标识符来删除的,浏览器上应该使用的是复选框。

        传入服务端的应该是一个唯一标识符的集合。

第一种处理方式 String ids = "1,2,3,4,5" 占位符应该使用${} delete from student where id in (${})

   void deleteBatch1(String ids);
    <delete id="deleteBatch1">
        delete from student where id in (${i})
    </delete>

第二种处理方式: 使用foreach标签

void deleteBatch2(@Param("ids") List<Integer> ids);
<!--    foreach中的collection属性默认为list list就是你传入的集合的。 如果没有指定(用@param指定),就会是默认的list-->
    <delete id="deleteBatch2" parameterType="list">
        delete from student where id in
        <foreach collection="ids" open="(" close=")" separator="," item="id" >
            #{id}
        </foreach>
    </delete>

 4.8.3 动态指定表名

动态指定表名应该就是根据不同的表名实现不同的查询结果。

/*动态指定表名*/
    List<Student> findAllByTableName(String tableName);
<!--    动态指定表名:  站位符使用${}
        List<Student> findAllByTableName(String tableName);-->
    <select id="findAllByTableName" resultType="com.mybatis.pojo.Student">
        select  * from ${tableName}
    </select>

4.8.4 主键返回

自增长类型主键

主键返回:

         之前的写法: 想要向数据库中新增一条记录 insert into student (id,name,gender,age,address)values(null,'安其拉','f',40,'北京')

         自增主键会传值null,想要获取主键值还需要再去表中查询。

mybatis为我们提供了可以在添加时获取主键的方式。(useGenerateKeys,keyproperty)

 void insertStudent(Student student);
<!--
    应用场景: 向数据库保存记录时,同时返回这条记录的主键值。应用于后续代码。
        useGeneratedKeys: 是否要使用数据库中生产的该条记录的主键值,true表示使用,false表示不使用
        keyproperty: 用于指定生成的主键值,存储的位置,一般指的是对应的实体类的属性值。
-->
    <insert id="insertStudent" useGeneratedKeys="true" keyProperty="id">
        insert into student values(null,#{name},#{gender},#{age},#{address})
    </insert>

 测试:

@Test
public void test12() throws IOException {
   InputStream stream = Resources.getResourceAsStream("mybatis-config.xml");
   SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(stream);
   SqlSession sqlSession = factory.openSession();
   StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

   Student student = new Student("张鲁一",40,"男","2222233333","北京");
   mapper.insertStudent(student);
   System.out.println(student.getId());

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

}

 非自增长类型主键

创建数据库的新表

use mybatis_db;
drop table if exists computer;
create table if not exists computer(
	id varchar(100) primary key,
	brand varchar(20),
   model varchar(20),
	price double
);

insert into computer values (1, 'ThinkPad','X1',12000);
insert into computer values (2, 'Mi','p1',6500);
insert into computer values (3, 'lenove','s1',4000);

commit;

select * from computer;

        而对于不支持自增型主键的数据库(例如 Oracle)或者字符串类型主键,则可以使用 selectKey 子元素:selectKey 元素将会首先运行,id 会被设置,然后插入语句会被调用!

使用 selectKey 帮助插入UUID作为字符串类型主键示例:

<insert id="insertUser" parameterType="User">
    <selectKey keyProperty="id" resultType="java.lang.String"
        order="BEFORE">
        SELECT UUID() as id
    </selectKey>
    INSERT INTO user (id, username, password) 
    VALUES (
        #{id},
        #{username},
        #{password}
    )
</insert>

        在上例中,我们定义了一个 insertUser 的插入语句来将 User 对象插入到 user 表中。我们使用 selectKey 来查询 UUID 并设置到 id 字段中。

        通过 keyProperty 属性来指定查询到的 UUID 赋值给对象中的 id 属性,而 resultType 属性指定了 UUID 的类型为 java.lang.String。

        需要注意的是,我们将 selectKey 放在了插入语句的前面,这是因为 MySQL 在 insert 语句中只支持一个 select 子句,而 selectKey 中查询 UUID 的语句就是一个 select 子句,因此我们需要将其放在前面。

        最后,在将 User 对象插入到 user 表中时,我们直接使用对象中的 id 属性来插入主键值。

        使用这种方式,我们可以方便地插入 UUID 作为字符串类型主键。当然,还有其他插入方式可以使用,如使用Java代码生成UUID并在类中显式设置值等。需要根据具体应用场景和需求选择合适的插入方式。

4.9 级联查询

4.9.1 多对一查询

        多对一,指的是表与表之间的记录关系,比如学生信息表(`S_ID`,`S_NAME`,……,`T_ID`)与教师(班主任)信息表(`T_ID`,`T_NAME`,……)。多个学生是一个老师教的。通过学生信息表里的任意一条记录,都可以找到教师信息表里的对应的老师信息。   

        第一种写法:字段映射

        第二种写法:association(关联,联合)

        第三种写法:分步写法

/*通过员工id 查找员工信息和其所在部门信息
    * 两种写法在mapper文件中。
    * */
    Employee findById(Integer id);
 <!--    字段映射写法。column: 指定数据库表中的字段名,property: 指定实体类中的属性名,
        由于要给属性dept赋值,而dept是一个Dept类型,因此实际上是给dept的各个属性赋值。
        -->
    <resultMap id="result1" type="employee">
        <id property="id" column="empno"/>
        <result property="name" column="ename"/>
        <result property="job" column="job"/>
        <result property="mgr" column="mgr"/>
        <result property="hireDate" column="hiredate"/>
        <result property="sal" column="sal"/>
        <result property="bonus" column="comm"/>
        <result property="deptId" column="deptno"/>
        <result property="dept.deptno" column="deptno"/>
        <result property="dept.dname" column="dname"/>
        <result property="dept.loc" column="loc"/>
    </resultMap>
    <select id="findById" resultMap="result1">
        select * from emp e join dept d on e.deptno = d.deptno where e.empno = #{id}
    </select>

 第二种写法 association

 <resultMap id="result2" type="employee">
        <!--        id子标签,专门用于主键映射
                    column: 指定数据库表中的字段名
                    property: 指定实体类中的属性名
         -->
        <id property="id" column="empno"/>
        <result property="name" column="ename"/>
        <result property="job" column="job"/>
        <result property="mgr" column="mgr"/>
        <result property="hireDate" column="hiredate"/>
        <result property="sal" column="sal"/>
        <result property="bonus" column="comm"/>
        <result property="deptId" column="deptno"/>

<!--       多对一的查询的第二种写法: 使用association(级联,关联,联合)标签。
            property: 用于指定给实体类的哪个属性做映射。
            javaType: 用于指定该属性的java类型。
            association的子标签: 用于将字段与实体类的属性的属性进行映射关系。
-->
        <association property="dept" javaType="Dept">
            <result property="deptno" column="deptno"/>
            <result property="dname" column="dname"/>
            <result property="loc" column="loc"/>
        </association>
    </resultMap>


<!--    -->
    <select id="findById" resultMap="result2">
        select * from emp e join dept d on e.deptno = d.deptno where e.empno = #{id}
    </select>

 第三种 分步查询

 // 多对一的查询的第三种写法: 分步查询
    // 通过id 查询员工信息,同时查询出员工所对应的部门信息
    Employee findByIdFirstEmpSecondDept(Integer id);
/*
        多对一的第三种写法的第二步
     */
    Dept findByIdSecondStep(Integer deptno);

区别代码:

<association property="dept" select="com.mybatis.mapper.DeptMapper.findByIdSecondStep" column="deptno"/>
<!--
    多对一的分步写法的第二步
-->
    <select id="findByIdSecondStep" resultType="Dept">
        select * from dept where deptno = #{id}
    </select>
<resultMap id="result3" type="employee">
        <id property="id" column="empno"/>
        <result property="name" column="ename"/>
        <result property="job" column="job"/>
        <result property="mgr" column="mgr"/>
        <result property="hireDate" column="hiredate"/>
        <result property="sal" column="sal"/>
        <result property="bonus" column="comm"/>
        <result property="deptId" column="deptno"/>

        <!--       多对一的查询的第三种写法: 也是使用association(级联,关联,联合)标签。
                    不同再写association里面的子标签了
                    只需配置下面几个属性即可
                    property: 用于指定给实体类的关联属性(Dept dept)
                    select: 对应的是第二步查询,语法结构:namespace.id(另一个映射的namespace地址值加上映射里的方法id值)
                    column: 第二步的sql需要一个条件,column用于指定第一步查询中要作为第二个sql语句的字段名。
        -->
        <association property="dept" select="com.mybatis.mapper.DeptMapper.findByIdSecondStep" column="deptno"/>
    </resultMap>

    <select id="findByIdFirstEmpSecondDept" resultMap="result3">
        select * from emp where empno = #{id}
    </select>

4.9.2 一对多查询

        一对多,其实就是多对一的反向操作。教师信息表是主表,学生信息表是副表,通过教师信息表的任意一条记录,都可以在学生信息表里找到该教师的多个学生信息。

第一种写法:collection

 // 案例演示: 查询某一个部门的信息,及其所有员工的信息。
    Dept findByIdCollection(Integer deptno);
<!--    一对多的写法 collection-->
    <resultMap id="deptMap1" type="Dept">
        <result property="deptno" column="deptno"/>
        <result property="dname" column="dname"/>
        <result property="loc" column="loc"/>
        <collection property="emps" ofType="Employee">
            <id property="id" column="empno"/>
            <result property="name" column="ename"/>
            <result property="job" column="job"/>
            <result property="mgr" column="mgr"/>
            <result property="hireDate" column="hiredate"/>
            <result property="sal" column="sal"/>
            <result property="bonus" column="comm"/>
            <result property="deptId" column="deptno"/>
        </collection>
    </resultMap>



    <select id="findByIdCollection" resultMap="deptMap1">
        select * from dept d join emp e on d.deptno = e.deptno where d.deptno=#{deptno}
    </select>

第二种写法:分步写法

 /*
        一对多的第二种写法: 分步查询
     */
    Dept findByIdFirstStep(Integer deptno);
 // 一对多查询的第二种写法分步查询
    // 第二步:通过第一步查询的结果中的deptno字段进行查询员工信息
    List<Employee> findByIdSecondStep(Integer deptno);

 区别代码:

<collection property="emps" select="com.mybatis.mapper.EmployeeMapper.findByIdSecondStep" column="deptno"/>
    <resultMap id="deptMap2" type="Dept">
        <result property="deptno" column="deptno"/>
        <result property="dname" column="dname"/>
        <result property="loc" column="loc"/>
        <collection property="emps" select="com.mybatis.mapper.EmployeeMapper.findByIdSecondStep" column="deptno">
        </collection>
    </resultMap>


<!--    一对多查询的分步第一步-->
    <select id="findByIdFirstStep" resultMap="deptMap2">
        select * from dept where deptno=#{deptno}
    </select>
<resultMap id="result4" type="employee">
        <id property="id" column="empno"/>
        <result property="name" column="ename"/>
        <result property="job" column="job"/>
        <result property="mgr" column="mgr"/>
        <result property="hireDate" column="hiredate"/>
        <result property="sal" column="sal"/>
        <result property="bonus" column="comm"/>
        <result property="deptId" column="deptno"/>
    </resultMap>

    <select id="findByIdSecondStep" resultMap="result4">
        select * from emp where deptno = #{id}
    </select>

4.9.3 多对多查询

        一般多对多,都会涉及到第三张表。 学生信息表(每个学生的信息都是唯一的一条记录), 课程信息表(每个科目也都是唯一的一条记录),学生课程表(一个学生可以选择多个科目进行学习,一个科目可以被多个学生选择学习)。学生信息表和课程信息表通过学生课程表进行的对应关系,就是多对多的关系。

建表sql:

CREATE TABLE `course`  (
  `c_id` int(0) NOT NULL AUTO_INCREMENT COMMENT '课程ID',
  `c_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '课程名称',
  `t_id` int(0) NOT NULL COMMENT '授课教师ID',
  `c_academy` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '所属学院',
  `c_note` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '课程备注',
  PRIMARY KEY (`c_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of course
-- ----------------------------
INSERT INTO `course` VALUES (1, '高数', 1, '信息学院', '高等数学,微积分');
INSERT INTO `course` VALUES (2, '英语', 2, '工程学院', '英语选修');
INSERT INTO `course` VALUES (3, 'JAVA', 3, '信息学院', '面向对象的编程语言');
INSERT INTO `course` VALUES (4, '食品安全', 1, '食品学院', '民以食为天');
INSERT INTO `course` VALUES (5, '土木建筑', 2, '工程学院', '桥梁,观景房');
INSERT INTO `course` VALUES (6, '体育', 2, '工程学院', '健身强体...');



CREATE TABLE `score`  (
  `s_id` int(0) NOT NULL COMMENT '学生ID',
  `c_id` int(0) NOT NULL COMMENT '课程ID',
  `score` int(0) NULL DEFAULT NULL COMMENT '课程分数',
  PRIMARY KEY (`s_id`, `c_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of score
-- ----------------------------
INSERT INTO `score` VALUES (1001, 1, 80);
INSERT INTO `score` VALUES (1001, 2, 90);
INSERT INTO `score` VALUES (1001, 3, 99);
INSERT INTO `score` VALUES (1002, 1, 70);
INSERT INTO `score` VALUES (1002, 2, 60);
INSERT INTO `score` VALUES (1002, 3, 80);
INSERT INTO `score` VALUES (1003, 1, 80);
INSERT INTO `score` VALUES (1003, 2, 80);
INSERT INTO `score` VALUES (1003, 4, 80);
INSERT INTO `score` VALUES (1004, 3, 50);
INSERT INTO `score` VALUES (1004, 4, 30);
INSERT INTO `score` VALUES (1004, 5, 20);
INSERT INTO `score` VALUES (1005, 5, 76);
INSERT INTO `score` VALUES (1005, 6, 87);
INSERT INTO `score` VALUES (1006, 5, 31);
INSERT INTO `score` VALUES (1006, 6, 34);
INSERT INTO `score` VALUES (1007, 4, 89);
INSERT INTO `score` VALUES (1007, 6, 98);

 StudentMapper接口

public interface StudentMapper {
    /*
        查询每个学生的基本信息,及其所学科目信息
     */
    List<Student> findAll();

    /*
        根据学生ID,查询学生的基本信息,及其所学科目信息(不包含成绩)
     */
    Student findById(Integer id);

    /*
        查询所有学生的学号,姓名,性别,年龄,课程号,选修科目名称,选修成绩
     */
    List<StudentInfo> findAllStudentInfo();
}

 mapper映射文件

<mapper namespace="com.mybatis.mapper.StudentMapper">

    <resultMap id="studentMap1" type="Student">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="age" column="age"/>
        <result property="gender" column="gender"/>
        <result property="address" column="address"/>
        <collection property="courses" ofType="course">
            <id property="cId" column="c_id"/>
            <result property="cName" column="c_name"/>
            <result property="tId" column="t_id"/>
            <result property="academy" column="c_academy"/>
            <result property="note" column="c_note"/>
        </collection>
    </resultMap>


    <select id="findAll" resultMap="studentMap1">
        select * from student s
        left join score sc on s.id = sc.s_id
        left join course c on sc.c_id = c.c_id
    </select>

    <select id="findById" resultMap="studentMap1">
        select * from student s
        left join score sc on s.id = sc.s_id
        left join course c on sc.c_id = c.c_id
        where s.id=#{id}
    </select>


    <resultMap id="studentMap2" type="studentInfo">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="age" column="age"/>
        <result property="gender" column="gender"/>
        <result property="cid" column="c_id"/>
        <result property="cName" column="c_name"/>
        <result property="score" column="score"/>
    </resultMap>
    <select id="findAllStudentInfo" resultMap="studentMap2">
        select s.id,s.name,s.age,s.gender,c.c_id,c.c_name,score
        from student s
        left join score sc on s.id = sc.s_id
        left join course c on sc.c_id = c.c_id
    </select>
</mapper>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2172361.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringMVC5-域对象共享数据

目录 使用ServletAPI向request域对象共享数据 使用ModelAndView向request域对象共享数据 使用Model向request域对象共享数据 使用map向request域对象共享数据 使用ModelMap向request域对象共享数据 Model、ModelMap、Map的关系 向session域共享数据 向application域共享…

【TabBar嵌套Navigation案例-新特性页面-基本框架 Objective-C语言】

一、我们来说这个示例程序里边的这个背景图片 1.首先呢,这个里边呢,我们这个新特性页面, 整个儿,是一个CollectionViewController,然后,我们做一下,先来做一下CollectionViewControlle,然后,我们把这个背景图片,先加上去, 这个时候,我要先创建一个新特性页面的模块…

开发提效的工具tabby快速入门

1.什么是tabby&#xff1f; Tabby is an open-source, self-hosted AI coding assistant. With Tabby, every team can set up its own LLM-powered code completion server with ease. 官方网站&#xff1a;https://tabby.tabbyml.com/ 2.tabby服务安装(Hugging Face Spaces…

28 - 移除元素

解答代码&#xff1a; int removeElement(int* nums, int numsSize, int val) {int j 0;for (int i 0; i < numsSize; i){if (nums[i] ! val){nums[j] nums[i];j;}}return j;}

机器学习笔记(李宏毅老师2021/2022课程)【更新中】

目录 前言 课程预览 第一讲 机器学习基本概念 前言 本文主要记录在听李宏毅老师的课时对应做的课堂笔记 课程&#xff1a; (强推)李宏毅2021/2022春机器学习课程_哔哩哔哩_bilibili 课程预览 机器学习找函数 &#xff08;找一个人类写不出来的复杂函数&#xff09; 课程侧…

代码随想录Day17 图论-2

103. 水流问题 本题思路很简单 要求我们找到可以满足到达两个边界的单元格的坐标 有一个优化的思路就是 我们从边界的节点向中间遍历 然后用两个数组表示 一个是第一组边界的数组 一个是第二边界的数组 如果两个数组都遍历到了某一个单元格 就说明该单元格时满足题目要求的 #…

【Linux笔记】在VMware中,为基于NAT模式运行的CentOS虚拟机设置固定的网络IP地址

一、配置VMware虚拟网络 1、打开VMware虚拟网络编辑器&#xff1a; 点击VMware主界面上方的“编辑”菜单&#xff0c;选择“虚拟网络编辑器”。 2、选择NAT模式网络&#xff1a; 在虚拟网络编辑器中&#xff0c;选择VMnet8&#xff08;或其他NAT模式的网络&#xff09;。 取消勾…

ubuntu18.04 NVIDIA驱动 CUDA cudnn Anaconda安装

1、安装NVIDIA驱动 a.查看推荐驱动 ubuntu-drivers devicesb.打开软件更新&#xff0c;选择相应的显卡 c.重启查看安装情况&#xff0c;输入nvidia-smi 2、安装CUDA 下载链接https://developer.nvidia.com/cuda-toolkit-archive 安装CUDA&#xff1a; sudo bash cuda_11…

ECharts图表图例3

java 用ecplise软件 可视化图表 代码&#xff1a; <! DOCTYPE html > < html > < head > < meta charset " UTF -8"> <1--引入 ECharts 脚本--> < script src " js / echarts . js "></ script > <…

力扣(leetcode)每日一题 2516 每种字符至少取 K 个 | 滑动窗口

2516. 每种字符至少取 K 个 给你一个由字符 a、b、c 组成的字符串 s 和一个非负整数 k 。每分钟&#xff0c;你可以选择取走 s 最左侧 还是 最右侧 的那个字符。 你必须取走每种字符 至少 k 个&#xff0c;返回需要的 最少 分钟数&#xff1b;如果无法取到&#xff0c;则返回…

专业团队如何提升多媒体翻译水平

随着对全球化内容需求的增长&#xff0c;提供准确且与文化相关的多媒体翻译的复杂性也在增加。Logrus IT团队对这一过程至关重要&#xff0c;确保翻译的各个方面——从语言适应到技术同步——都能以精确、创造性和文化洞察力来处理。以下是我们的专业团队如何在为全球观众转换多…

数据加密标准(DES)详解:原理、步骤及Python实现

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storm…

【H2O2|全栈】关于CSS(8)CSS3扩充了哪些新鲜的东西?

目录 CSS3入门 前言 准备工作 边框属性的扩充 border-image 盒子阴影 背景属性 渐变属性 线性渐变 径向渐变 重复渐变 案例 自定义字体 预告和回顾 后话 CSS3入门 前言 本系列博客主要介绍CSS相关的知识点。 从本期开始&#xff0c;CSS的知识从CSS的2.x时代…

27 基于51单片机的方向盘模拟系统

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于STC89C52单片机&#xff0c;采用两个MPX4115压力传感器作为两路压力到位开关电路&#xff0c; 采用滑动变阻器连接数模转换器模拟重力加速度传感器电路&#xff1b; 一个按键控制LED灯的点亮与…

看Threejs好玩示例,学习创新与技术(ThreePipe)

下面这个示例我觉得特别棒&#xff0c;我会推荐给我们的美工&#xff0c;以后产品的宣传图用它。比如下面这个图&#xff0c;不需要PS&#xff0c;仅需拖拽一个照片进去&#xff0c;它会自动铺到笔记本电脑上。完成后点击截图就可以得到高清图片&#xff0c;不需要摆拍和PS。大…

机械加工常识

1 机加工工艺 增材&#xff1a;浇铸、3D打印 减材&#xff1a;齿轮机、车床、铣床、磨床 冷加工 热加工&#xff1a;焊接 拔制 2 公差设定与加工精度等级 H7/g6: 1个叫公差&#xff0c;两个合到一起叫公差配合 7和6是加工精度等级 基孔制&#xff1a;a&#xff5e;h形成间隙…

linux-CMake

linux-CMake 1.安装CMake工具2.单个源文件3.多个源文件4.生成库文件5.将源文件组织到不同的目录下6.可执行文件和库文件放置到单独的目录下7.常见的命令 CMake使用。 1.安装CMake工具 sudo apt-get install cmake2.单个源文件 1.先在文件夹里创建两个文件&#xff1a;main.c&…

excel统计分析(3): 一元线性回归分析

简介 用途&#xff1a;研究两个具有线性关系的变量之间的关系。 一元线性回归分析模型&#xff1a; ab参数由公式可得&#xff1a; 判定系数R2&#xff1a;评估回归模型的拟合效果。值越接近1&#xff0c;说明拟合效果越好&#xff1b;值越接近0&#xff0c;说明拟合效果越…

回归预测|基于小龙虾优化LightGBM的数据回归预测Matlab程序COA-LightGBM 多特征输入单输出 含基础模型

回归预测|基于小龙虾优化LightGBM的数据回归预测Matlab程序COA-LightGBM 多特征输入单输出 含基础模型 文章目录 一、基本原理COA-LightGBM 多特征输入单输出回归预测的原理和流程2.1 蟋蟀优化算法&#xff08;COA&#xff09;2.2 LightGBM3.1 数据准备3.2 模型构建3.3 参数优化…

6.8方框滤波

基本概念 方框滤波&#xff08;Box Filter&#xff09;是一种基本的图像处理技术&#xff0c;用于对图像进行平滑处理或模糊效果。它通过在图像上应用一个固定大小的方框核&#xff08;通常是矩形&#xff09;&#xff0c;计算该区域内像素值的平均值来替换中心像素的值。这种…