Mybatis查询(最全面)

336 阅读9分钟

Mybatis查询

MyBatis支持多种类型的查询,以下是一些常见的MyBatis查询方式:

  1. 基本查询(Basic Query)
    使用SQL语句进行基本的数据库查询,通过selectinsertupdatedelete等操作来执行CRUD操作。
  2. 注解查询(Annotation Query)
    使用注解(例如@Select@Insert@Update@Delete等)在Mapper接口中直接编写SQL语句来执行查询。
  3. XML配置文件查询(XML Configuration Query)
    使用XML配置文件来编写SQL语句,然后在Mapper接口中引用这些SQL语句进行查询。
  4. 动态SQL查询(Dynamic SQL Query)
    MyBatis提供了动态SQL的功能,可以根据条件来动态地生成SQL语句,实现灵活的查询。
  5. 参数传递查询(Parameter Passing Query)
    通过参数传递方式将数据传递给SQL语句,例如使用@Param注解传递参数,或者使用#{}占位符进行参数绑定。
  6. 结果映射查询(Result Mapping Query)
    将查询结果映射为Java对象,可以使用<resultMap>标签或@Results注解来进行结果映射。
  7. 关联查询(Association Query)
    在查询中使用嵌套查询或者联合查询来关联多个表,将结果映射为复杂的Java对象结构。
  8. 分页查询(Pagination Query)
    MyBatis支持对查询结果进行分页处理,可以使用RowBounds或者插件等方式实现分页查询。
  9. 缓存查询(Caching Query)
    MyBatis支持查询结果的缓存,可以减少对数据库的访问,提高性能。
  10. 存储过程调用(Stored Procedure)
    MyBatis支持调用数据库中的存储过程,可以在Mapper接口中执行存储过程。

查询比较官方的写法

环境准备

-- 员工管理
create table emp (
  id int unsigned primary key auto_increment comment 'ID',
  username varchar(20) not null unique comment '用户名',
  password varchar(32) default '123456' comment '密码',
  name varchar(10) not null comment '姓名',
  gender tinyint unsigned not null comment '性别, 说明: 1 男, 2 女',
  image varchar(300) comment '图像',
  job tinyint unsigned comment '职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师',
  entrydate date comment '入职时间',
  dept_id int unsigned comment '部门ID',
  create_time datetime not null comment '创建时间',
  update_time datetime not null comment '修改时间'
) comment '员工表';

INSERT INTO emp
(id, username, password, name, gender, image, job, entrydate,dept_id, create_time, update_time) VALUES
(1,'jinyong','123456','金庸',1,'1.jpg',4,'2000-01-01',2,now(),now()),
(2,'zhangwuji','123456','张无忌',1,'2.jpg',2,'2015-01-01',2,now(),now()),
(3,'yangxiao','123456','杨逍',1,'3.jpg',2,'2008-05-01',2,now(),now()),
(4,'weiyixiao','123456','韦一笑',1,'4.jpg',2,'2007-01-01',2,now(),now()),
(5,'changyuchun','123456','常遇春',1,'5.jpg',2,'2012-12-05',2,now(),now()),
(6,'xiaozhao','123456','小昭',2,'6.jpg',3,'2013-09-05',1,now(),now()),
(7,'jixiaofu','123456','纪晓芙',2,'7.jpg',1,'2005-08-01',1,now(),now()),
(8,'zhouzhiruo','123456','周芷若',2,'8.jpg',1,'2014-11-09',1,now(),now()),
(9,'dingminjun','123456','丁敏君',2,'9.jpg',1,'2011-03-11',1,now(),now()),
(10,'zhaomin','123456','赵敏',2,'10.jpg',1,'2013-09-05',1,now(),now()),
(11,'luzhangke','123456','鹿杖客',1,'11.jpg',5,'2007-02-01',3,now(),now()),
(12,'hebiweng','123456','鹤笔翁',1,'12.jpg',5,'2008-08-18',3,now(),now()),
(13,'fangdongbai','123456','方东白',1,'13.jpg',5,'2012-11-01',3,now(),now()),
(14,'zhangsanfeng','123456','张三丰',1,'14.jpg',2,'2002-08-01',2,now(),now()),
(15,'yulianzhou','123456','俞莲舟',1,'15.jpg',2,'2011-05-01',2,now(),now()),
(16,'songyuanqiao','123456','宋远桥',1,'16.jpg',2,'2010-01-01',2,now(),now()),
(17,'chenyouliang','123456','陈友谅',1,'17.jpg',NULL,'2015-03-21',NULL,now(),now());

查询所有方法

//查询
@Select("select * from emp")
    List<Emp> findAll();

测试

    //查询所有
    @Test
    public void testFindAll() {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);

        List<Emp> empList = empMapper.findAll();
        empList.forEach(e -> System.out.println(e));//lambda方式打印

        MybatisUtil.close(sqlSession);
    }

驼峰映射

当表中字段和类中属性的关系是_和驼峰写法时,可以开启mybatis的自动驼峰映射

<setting name="mapUnderscoreToCamelCase" value="true"/>

起别名

当表中字段和类中属性完全没有关系时,可以使用别名来修改sql返回集中字段的名称

给不对应的字段起别名

    //查询
    @Select("select id, username, password, name, gender, image, job, entrydate as ed, dept_id, create_time, update_time from emp")
    List<Emp> findAll2();

测试

 //查询所有
    @Test
    public void testFindAll2() {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);

        List<Emp> empList = empMapper.findAll2();
        empList.forEach(e -> System.out.println(e));//lambda方式打印

        MybatisUtil.close(sqlSession);
    }

自定义映射

当表中字段和类中属性完全没有关系时,可以通过@Results进行手动结果映射

自定义结果映射

    //查询
    @Results({//@Results: 自定义结果映射
            @Result(column = "entrydate", property = "ed"),//@Result一条映射规则 (column = "数据表中字段名", property = "实体类属性名")
            @Result(column = "dept_id", property = "deptId")
    })
    @Select("select * from emp")
    List<Emp> findAll3();

测试

    //查询所有
    @Test
    public void testFindAll3() {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);

        List<Emp> empList = empMapper.findAll3();
        empList.forEach(e -> System.out.println(e));//lambda方式打印

        MybatisUtil.close(sqlSession);
    }

条件查询

当查询方法出现多个查询条件时,需要使用@Param注解设置对应关系

添加条件查询的方法

	//#{} 里面的内容
    //1. 如果参数是一个对象类型, #{}写的是对象中的属性名
    //2. 如果参数是一个简单类型(8基本 + 8包装 +String) ,#{}可以随便写, 但是推荐写方法形参名
    //3. 如果参数是多个简单类型的参数, #{}中写的是@Param注解中的值
    //条件查询
    @Select("select * from emp where name = #{name} and gender = #{gender} and entrydate between #{begin} and #{end}")
    List<Emp> findList(@Param("name") String name, @Param("gender") Short gender, @Param("begin") LocalDate begin, @Param("end") LocalDate end);

测试

    //条件查询
    @Test
    public void testFindList() {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);

        List<Emp> empList = empMapper.findList("张三丰", (short) 1, LocalDate.of(2002, 01, 01), LocalDate.of(2023, 12, 31));
        empList.forEach(e -> System.out.println(e));//lambda方式打印

        MybatisUtil.close(sqlSession);
    }

模糊查询

当查询sql中出现模糊查询语法时,需要使用concat函数连接条件,比如根据用户名进行模糊查询

`where name like '%张%'----------------->where name like concat('%',#{username},'%')

添加条件查询的方法

    //模糊查询
    @Select("select * from emp where name like concat('%',#{name},'%') and gender = #{gender} and entrydate between #{begin} and #{end}")
    List<Emp> findListLike(@Param("name") String name, @Param("gender") Short gender, @Param("begin") LocalDate begin, @Param("end") LocalDate end);

测试

    //模糊查询
    @Test
    public void testFindListLike() {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);

        List<Emp> empList = empMapper.findListLike("张", (short) 1, LocalDate.of(2002, 01, 01), LocalDate.of(2023, 12, 31));
        empList.forEach(e -> System.out.println(e));//lambda方式打印

        MybatisUtil.close(sqlSession);
    }

所有写一起

Emp类
package com.itheima.domain;

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

import java.time.LocalDate;
import java.time.LocalDateTime;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
    private Integer id;
    private String username;
    private String password;
    private String name;
    private Short gender;
    private String image;
    private Short job;

    //注意:这四个属性跟数据表中的字段不一致
    private LocalDate ed;
    private Integer deptId;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
}
Mapper类
package com.itheima.mapper;

import com.itheima.domain.Emp;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;

import java.time.LocalDate;
import java.util.Date;
import java.util.List;
import java.util.Map;

public interface EmpMapper {
    @Select("select * from emp")
    List<Emp> findAll();

    //起别名
    @Select("select id,username,password,name,gender,image,job," +
            "entrydate as ed,dept_id,create_time,update_time from emp")
    List<Emp> findAll2();

    //起别名二
    @Select("select *,entrydate as ed from emp")
    List<Emp> findAll3();

    //建立映射
    @Results({
            @Result(column = "entrydate",property = "ed"),
            @Result(column = "update_time",property = "updateTime")
    })
    @Select("select * from emp")
    List<Emp> findAll4();

    //添加条件查询的方法
    //#{} 里面的内容
    //1. 如果参数是一个对象类型, #{}写的是对象中的属性名
    //2. 如果参数是一个简单类型(8基本 + 8包装 +String) ,#{}可以随便写, 但是推荐写方法形参名
    //3. 如果参数是多个简单类型的参数, #{}中写的是@Param注解中的值
    @Select("select * from emp where name = #{name} and gender = #{gender} and " +
            "entrydate between #{begin} and #{end}")
    List<Emp> findList(@Param("name") String name, @Param("gender") Short gender,
                       @Param("begin") LocalDate begin, @Param("end") LocalDate end);

    //模糊查询
    @Select("select * from emp where name like concat('%',#{name},'%') and gender = #{gender} " +
            " and entrydate between #{begin} and #{end}")
    List<Emp> findListLike(@Param("name") String name, @Param("gender") Short gender,
                         @Param("begin") LocalDate begin, @Param("end") LocalDate end);

    //注意: 对于同一个方法,使用xml写sql的话,就不能在使用注解写sql了
    //@Select("select * from emp where id = #{id}")
    Emp findById(@Param("id") Integer id);

    List<Emp> findByCondition(@Param("name") String name,
                              @Param("gender") Short gender,
                              @Param("begin") LocalDate begin,
                              @Param("end") LocalDate end);

    //根据ID更新不为空的字段  修改
    void update(Emp emp);

    //删除
    void deleteByIds(@Param("ids") List<Integer> ids);


    //案例的  myBatis forEach 插入
    void insertEmp(@Param("empList") List<Emp> empList);

}
Util类
package com.itheima.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.InputStream;

public class MybatisUtil {

    private static SqlSessionFactory sqlSessionFactory = null;

    //保证SqlSessionFactory仅仅创建一次
    static {
        try {
            //读取配置文件
            InputStream stream = Resources.getResourceAsStream("SqlMapConfig.xml");
            //创建SqlSessionFactory
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(stream);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //获取sqlSession
    public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession();
    }

    //提交事务 关闭sqlSession
    public static void close(SqlSession sqlSession) {
        if (sqlSession != null) {
            //提交事务
            sqlSession.commit();
            //释放资源
            sqlSession.close();
        }
    }
}
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.itheima.mapper.EmpMapper">

    <sql id="selectUser">
        select id,
               username,
               password,
               name,
               gender,
               image,
               job,
               entrydate as ed,
               dept_id,
               create_time,
               update_time
        from emp
    </sql>

    <!-- id : 哪个方法-->
    <!-- resultType:方法返回值类型-->
    <select id="findById" resultType="com.itheima.domain.Emp">
        <include refid="selectUser"></include>
        where id = #{id}
    </select>


    <!--
    字符串需要跟null和空串比较
    其他类型只要跟null比较

    if:使用test进行条件判断,只有条件成立,条件中的sql才会生效
    where:只会在<where>标签内部有内容的情况下才插入where子句,而且会自动去除子句的开头的AND或OR。
    -->
    <select id="findByCondition" resultType="com.itheima.domain.Emp">
        select * from emp
        <where>
            <if test="name!=null and name!=''">
                name like concat('%',#{name},'%')
            </if>
            <if test="gender != null">
                and gender = #{gender}
            </if>
            <if test="begin !=null and end != null">
                and entrydate between #{begin} and #{end}
            </if>
        </where>
    </select>


    <!---->
    <update id="update">
        update emp
        <set>
            <if test="username !=null and username !=''">
                username = #{username},
            </if>
            <if test="password !=null and password !=''">
                password = #{password},
            </if>
            <if test="name !=null and name !=''">
                name = #{name},
            </if>
            <if test="gender !=null">
                gender = #{gender},
            </if>
            <if test="image !=null and image !=''">
                image = #{image},
            </if>
            <if test="job !=null">
                job= #{job},
            </if>
            <if test="ed !=null">
                entrydate = #{ed},
            </if>
            <if test="createTime !=null">
                create_Time = #{createTime},
            </if>
            <if test="updateTime !=null">
                update_time = #{update },
            </if>
        </set>
        where id = #{id}
    </update>


    <!--
* collection:集合名称
* item:集合遍历出来的元素
* separator:每一次遍历使用的分隔符
* open: 遍历开始前拼接的片段
* close:遍历结束后拼接的片段
    -->

    <delete id="deleteByIds">
        delete from emp where id in
        <foreach collection="ids" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </delete>


    <!--
* 案例的  myBatis forEach 插入
    -->
    <insert id="insertEmp">
        insert into emp(id,username,password,name,
        gender,create_time,update_time)
        values
        <foreach collection="empList" item="emp" separator=",">
            (null ,#{emp.username},#{emp.password},#{emp.name},
            #{emp.gender},now(),now())
        </foreach>
    </insert>

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



<!--
    * 定义SQL片段:  <sql id="selectUser"></sql>
    * 引用SQL片段:  <include refid="selectUser"></include>
-->



    <settings>
        <!-- 驼峰映射-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>

        <!--在控制台输出发送的sql日志-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>


    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>

            <!--目前只关注这部分内容,它的作用就是声明要连接的数据信息-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="1234"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!--声明含有sql的接口所在包-->
        <package name="com.itheima.mapper"/>
    </mappers>
</configuration>
测试类
package com.itheima.test;

import com.itheima.domain.Emp;
import com.itheima.mapper.EmpMapper;
import com.itheima.util.MybatisUtil;
import jdk.swing.interop.SwingInterOpUtils;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class EmpMapperTest {
    @Test
    public void testFindall(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        List<Emp> all = mapper.findAll();

        all.forEach(new Consumer<Emp>() {
            @Override
            public void accept(Emp emp) {
                System.out.println(emp);
            }
        });

        MybatisUtil.close(sqlSession);
    }


    @Test
    public void testFindall1(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        //方法二
        List<Emp> all = mapper.findAll2();

        //lambda写法
        all.forEach(emp -> System.out.println(emp));

        MybatisUtil.close(sqlSession);
    }


    @Test
    public void testFindall2(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        //方法三 起别名
        List<Emp> all = mapper.findAll3();

        //静态方法写法
        all.forEach(System.out::println);

        MybatisUtil.close(sqlSession);
    }

    @Test
    public void testFindall3(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        //方法四 映射
        List<Emp> all = mapper.findAll4();

        //静态方法写法
        all.forEach(System.out::println);

        MybatisUtil.close(sqlSession);
    }

    //添加条件查询的方法
    @Test
    public void testFindList(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        List<Emp> emps = mapper.findList("张三丰", (short) 1, LocalDate.of(2002, 1, 1),
                LocalDate.of(2023, 12, 31));

        emps.forEach(new Consumer<Emp>() {
            @Override
            public void accept(Emp emp) {
                System.out.println(emp);
            }
        });

        MybatisUtil.close(sqlSession);
    }


    //模糊查询
    @Test
    public void testFindListLike(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        List<Emp> emps = mapper.findListLike("张", (short) 1, LocalDate.of(2002, 01, 01),
                LocalDate.of(2023,12,31));

        emps.forEach(emp -> System.out.println(emp));

        MybatisUtil.close(sqlSession);
    }

    //根据id查询
    @Test
    public void testFindById() {
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);

        Emp emp = empMapper.findById(1);
        System.out.println(emp);

        MybatisUtil.close(sqlSession);
    }

    //条件查询
    @Test
    public void testFindByCondition(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        //查姓张的
        List<Emp> empList = mapper.findByCondition("张", (short) 1, null, null);
        empList.forEach(e -> System.out.println(e));

        MybatisUtil.close(sqlSession);
    }


    //更新测试
    @Test
    public void testUpdate(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        Emp emp = new Emp();
        emp.setId(1);
        emp.setUsername("程序员");
        emp.setName("陈某人");

        mapper.update(emp);

        MybatisUtil.close(sqlSession);
    }


    //根据ID批量删除
    @Test
    public void deleteByIds(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        mapper.deleteByIds(Arrays.asList(10,11,12));

        MybatisUtil.close(sqlSession);
    }


    /**
     * 案例的  myBatis forEach 插入
     */
    @Test

    public void insertEmp(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        ArrayList<Emp> empList = new ArrayList<>();

        for (int i = 0; i < 1000; i++) {
            Emp emp = new Emp();
            emp.setUsername("啦啦啦啦"+i);
            emp.setPassword("123456");
            emp.setName("李思"+i);
            emp.setGender((short) 2);
            empList.add(emp);
        }

        mapper.insertEmp(empList);

        MybatisUtil.close(sqlSession);
    }
}