Mybatis单表操作之普通操作、模糊查询、分页查询、动态SQL

简介: Mybatis单表操作之普通操作、模糊查询、分页查询、动态SQL

前言

最近有点学累了,很久没有学习新东西了,花了一个晚上的时间归纳和整理了Mybatis对表的操作,主要是对单表进行操作,包括基本的单表操作CRUD,以及模糊查询、分页查询及动态SQL等 。后面会陆续把一对多,多对一查询及多表查询整理一下。

1、构建数据库

在学习之前,你首先要先建一个数据库,本文用Navicat建了一个数据库ssmbuild,里面放了一张books表。然后,把核心配置文件、实体类、工具类等等先写好,该部分可以参考博主以往的博客

CREATE DATABASE `ssmbuild`;
USE `ssmbuild`;
DROP TABLE IF EXISTS `books`;
CREATE TABLE `books` (
`bookID` INT(10) NOT NULL  COMMENT '书id',
`bookName` VARCHAR(100) NOT NULL COMMENT '书名',
`bookCounts` INT(11) NOT NULL COMMENT '数量',
`detail` VARCHAR(200) NOT NULL COMMENT '描述',
 PRIMARY KEY `bookID` (`bookID`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT  INTO `books`(`bookID`,`bookName`,`bookCounts`,`detail`)VALUES
(1,'Java',1,'从入门到放弃'),
(2,'MySQL',10,'从删库到跑路'),
(3,'Linux',5,'从进门到进牢'),
(4,'Java',15,'Java修仙手册'),
(5,'C++',25,'C++致命宝典');

55f20c76c34df199322dbe52f80429c6_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5YWo5p2R56ys5LqM5biF,size_20,color_FFFFFF,t_70,g_se,x_16.png

2、 普通操作

(1) 查询书籍

查询书籍,既可以查询全部书籍,也可以根据id去查询,当然后面会用到动态查询(可以根据某个字段进行模糊查询)。由于SQL语句较简单,所以这里用注解的方式实现 ,因为查询所有书籍会返回若干条记录,所以用集合来保存,最后用增强for去打印集合

//查询所有的书籍
    @Select("select *from ssmbuild.books")
    List<Books> queryAllBooks();
//根据BookId查询相应的书籍
    @Select("select *from ssmbuild.books where bookID=#{id}")
    Books queryBooksById(@Param("id") int BookID);
@Test
    public void test1() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BookMapper mapper = sqlSession.getMapper(BookMapper.class);
        List<Books> allBooks = mapper.queryAllBooks();
        for (Books books : allBooks) {
            System.out.println(books);
        }
        sqlSession.close();
    }
 @Test
    public void test5(){
        SqlSession sqlSession=MybatisUtils.getSqlSession();
        BookMapper mapper = sqlSession.getMapper(BookMapper.class);
        Books books = mapper.queryBooksById(5);
        System.out.println(books);
        sqlSession.close();
    }

(2) 增加书籍

可以用带参构造方法和map键值对来增加书籍,返回类型void和int均可,注意实体类的成员变量属性要与数据库字段名一致,否者用resultmap将column与properties对应起来也是可以滴

    //用带参构造方法增加书籍
    int addBooks(Books books);
    //用map键值对增加书籍
    int addBooks2(Map<String, Object> map);


<insert id="addBooks" parameterType="books">
        insert into ssmbuild.books (bookID, bookName, bookCounts, detail)
        VALUES (#{bookID}, #{bookName}, #{bookCounts}, #{detail})
    </insert>
    <insert id="addBooks2" parameterType="map">
        insert into ssmbuild.books (bookID, bookName, bookCounts, detail)
        VALUES (#{bookID}, #{bookName}, #{bookCounts}, #{detail})
    </insert>
 @Test
    public void test6(){
        SqlSession sqlSession=MybatisUtils.getSqlSession();
        BookMapper mapper = sqlSession.getMapper(BookMapper.class);
        int res = mapper.addBooks(new Books(8, "kali", 1000, "kali学的好,号子蹲的早"));
        if (res>0){
            System.out.println("增加书籍成功!");
        }
        sqlSession.commit();
        sqlSession.close();
    }
    @Test
    public void test7(){
        SqlSession sqlSession=MybatisUtils.getSqlSession();
        BookMapper mapper = sqlSession.getMapper(BookMapper.class);
        Map<String,Object> map=new HashMap<>();
        map.put("bookID",9);
        map.put("bookName","一支红杏出墙来");
        map.put("bookCounts",300);
        map.put("detail","小王老师又一巨作");
        int res = mapper.addBooks2(map);
        if (res>0){
            System.out.println("插入成功!");
        }
        sqlSession.commit();
        sqlSession.close();
    }

注:增删改, 均变动了数据库记录,需要提交事务,有两种方式:上面代码commit方式是一种,还有一种一劳永逸的方式,即将工具类里调用openSession的方法改为true。

(3) 删除书籍

这里是根据id去删除书籍,后面可以用动态sql之foreach去批量删除书籍

int deleteBooks(@Param("id") int BookID);
<delete id="deleteBooks" parameterType="books">
        delete
        from ssmbuild.books
        where bookID = #{id}
    </delete>

(4)更新书籍

普通的更新,除了主键外,所有的字段都需要进行更新,后面可以用动态更新,哪里想更,更哪里,妈妈再也不要担心我的学习了。

int updateBooks(Books books);
<update id="updateBooks" parameterType="books">
        update ssmbuild.books
        set bookName  = #{bookName},
            bookCounts=#{bookCounts},
            detail=#{detail}
        where bookID = #{bookID}
    </update>
@Test
    public void test10(){
        SqlSession sqlSession=MybatisUtils.getSqlSession();
        BookMapper mapper = sqlSession.getMapper(BookMapper.class);
        int res = mapper.updateBooks(new Books(7, "数据库", 1000, "从入库到跑路"));
        if (res>0){
            System.out.println("更新成功!");
        }
        sqlSession.commit();
        sqlSession.close();
    }

3、模糊查询

(1)模糊查询"%",可匹配任意类型和长度的字符

@Select("select *from ssmbuild.books where detail like '%小王老师%'")
    List<Books> queryLikeBooks();

查询结果:

(2)模糊查询"_",可匹配单个任意字符,它常用来限制表达式的字符长度

@Select("select *from ssmbuild.books where detail like '从_门到__'")
    List<Books> queryLikeBooks1();

查询结果:

注:模糊查询有很多种,常用的有这两种,博主偷懒,所以用的注解的方式

4、分页查询

分页查询有limit和RowBounds分页,limit分页用的较多,limit a,b,a表示起始索引,从0开始,表示第一条记录, b表示是指从第a+1条开始,取b条。

 @Select("select *from ssmbuild.books limit 5,2")
    List<Books> queryLimitBooks();

查询结果:上述表示从第六条记录开始,取两条记录,所以查询结果的id应该为6,7

5、动态SQL

动态 SQL 是 MyBatis 的强大特性之一。如果你使用过JDBC或其它类似的框架,你应该就能理解根据不同条件拼接SQL语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。上述的CRUD都比较简单,当面对复杂的业务时,就需要写一些复杂的 SQL 语句,这时候往往需要拼接,而拼接 SQL ,稍微不注意,由于引号,空格等缺失可能都会导致错误。mybatis 利用动态SQL,通过 if, choose,when,otherwise, trim,where, set,foreach等标签,可组合成非常灵活的SQL语句,从而在提高 SQL 语句的准确性的同时,也大大提高了开发人员的效率。

(1)动态SQL之IF

 //动态SQL之IF选择查询
   List<Books> queryIfBooks(Map<String, Object> map);
<select id="queryIfBooks" parameterType="map" resultType="books">
        select *from ssmbuild.books where 1=1
            <if test="bookName!=null">
                bookName like #{bookName}
            </if>
            <if test="detail!=null">
                and detail like #{detail}
            </if>
    </select>
@Test
    public void test11() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BookMapper mapper = sqlSession.getMapper(BookMapper.class);
        HashMap<String,Object> map =new HashMap<String,Object>();
        map.put("detail","%小王%");
        //map.put("bookName","%Java%");
        List<Books> allBooks = mapper.queryIfBooks(map);
        for (Books books : allBooks) {
            System.out.println(books);
        }
        sqlSession.close();
    }


为啥这里要用sql注入(where1=1)的方式 ?这里“where 1”,“where true”也都可以 ,去掉1=1,你就能发现问题所在了。只要跳过bookName字段,对detail字段进行查询时,系统就拼接不起来了,正常语句where后面都要加上判断的条件。所以where1=1的方式能保证对查询条件进行拼接并保证查询能进行下去。当然这里推荐使用where标签,where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句,什么意思呢?就是说在匹配不到合适的字段条件时,where字段不加上去,就成了“select *from  ssmbuild.books”了,变成查询所有字段了。若子句的开头为 “AND” 或 “OR”,where 元素会将它们去除。像下面的错误,用上where标签,就会舍弃and,成了“select *from  ssmbuild.books where detail like 条件”,能查询出与detail标签相关的内容了。

0b83ce25e64de7d18ee5cc3e4fe4655e_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5YWo5p2R56ys5LqM5biF,size_20,color_FFFFFF,t_70,g_se,x_16.png

加上where标签,用IF同时对bookName和detail进行模糊查询时,你会发现什么都查不出来,也许你会说博主这不是在胡说八道吗,但我想在这先卖个关子,这就是上面为啥要先注释掉一条了。

(2) 动态Sql之set


set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。

int updateSetBooks(Map<String,Object> map);
<update id="updateSetBooks" parameterType="map">
        update ssmbuild.books
        <set>
            <if test="bookName!=null">bookName=#{bookName},</if>
            <if test="bookCounts!=null">bookCounts=#{bookCounts},</if>
            <if test="detail!=null">detail=#{detail}</if>
        </set>
        where bookID=#{bookID}
    </update>
@Test
    public void test12() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BookMapper mapper = sqlSession.getMapper(BookMapper.class);
        HashMap<String,Object> map =new HashMap<String,Object>();
        map.put("bookID",7);
        map.put("bookName","大数据");
        int res = mapper.updateSetBooks(map);
        if (res>0){
            System.out.println("更新成功!");
        }
        sqlSession.commit();
        sqlSession.close();
    }

这里用set对7号书籍的书籍名称进行修改,原表是数据库,现在应该是改成大数据了。

(3)动态SQL之Choose

动态SQL之Choose,跟if查询类似,但if需要同时满足多个查询条件,而choose满足一个就会查出,现在就解开上面卖的关子。

List<Books> queryChooseBooks(Map<String,Object> map);
<select id="queryChooseBooks" parameterType="map" resultType="books">
        select *from ssmbuild.books
        <where>
            <choose>
                <when test="bookName!=null">
                    bookName like #{bookName}
                </when>
                <when test="bookCounts!=null">
                   AND bookCounts like #{bookCounts}
                </when>
                <when test="detail!=null">
                    AND detail like #{detail}
                </when>
                <otherwise>AND featured = 1 </otherwise>
            </choose>
        </where>
    </select>
 @Test
    public void test13() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BookMapper mapper = sqlSession.getMapper(BookMapper.class);
        HashMap<String,Object> map =new HashMap<String,Object>();
        map.put("detail","%小王%");
        map.put("bookName","%Java%");
        List<Books> allBooks = mapper.queryChooseBooks(map);
        for (Books books : allBooks) {
            System.out.println(books);
        }
        sqlSession.close();
    }

这里的junit测试单元是不是在哪见过?对的,跟if查询不要说一毛一样,简直就是双胞胎,也就方法名不同而已。那结果呢?话不多说,看图。if要条件全部满足才能查出,而choose查到一个就不会继续查了,有点类似多分支Switch语句。

8991db91d7dd83b8125f9cbab20261d9_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5YWo5p2R56ys5LqM5biF,size_20,color_FFFFFF,t_70,g_se,x_16.png

(4) 动态SQL之foreach

动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值(官方文档说的很清楚)。我们这用foreach实现批量删除,当然还可以用来实现批量增加记录。

//使用foreach批量删除书籍
    void deleteSomeBooks(List<Integer> list);

注:尽量不要像博主一样在配置文件中加中文 ,有时会报错,具体怎么解决,参考以往文章

<delete id="deleteSomeBooks" parameterType="map">
        <!--collection: 表示类型,如果参数是数组,就写成array,如果是集合,就写成list
        item: 表示集合中每一个元素进行迭代时的别名,自己随便取名
        index,指定一个名字,用于表示在迭代过程中,每次迭代到的位置
        -->
        delete
        from ssmbuild.books
        where bookID in
        <foreach collection="list" item="id" open="(" separator="," close=")">
            #{id}
        </foreach>
    </delete>

这里是删除id=9到id=18之间的书籍记录

 @Test
    public void test8(){
        SqlSession sqlSession=MybatisUtils.getSqlSession();
        BookMapper mapper = sqlSession.getMapper(BookMapper.class);
        ArrayList<Integer> list = new ArrayList<>();
        for (int num=9;num<19;num++){
            list.add(num);
        }
        mapper.deleteSomeBooks(list);
        sqlSession.commit();
        sqlSession.close();
    }

(5)动态SQL之trim

自定义trim元素,trim可以定制set和where功能,即不用手动去写"and","or",","等。其实set里的“,”及where里的“and”不加也不会报错,但为了书写规范还是加吧。所以感觉trim有点鸡肋。

int updateTrimBooks(Map<String,Object> map);
<update id="updateTrimBooks" parameterType="map">
        update ssmbuild.books
        <trim prefix="SET" suffixOverrides=",">
            <if test="bookName!=null">bookName=#{bookName}</if>
            <if test="bookCounts!=null">bookCounts=#{bookCounts}</if>
            <if test="detail!=null">detail=#{detail}</if>
        </trim>
        where bookID=#{bookID}
    </update>
@Test
    public void test14() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BookMapper mapper = sqlSession.getMapper(BookMapper.class);
        HashMap<String,Object> map =new HashMap<String,Object>();
        map.put("bookID",7);
        map.put("bookName","数据库");
        int res = mapper.updateTrimBooks(map);
        if (res>0){
            System.out.println("更新成功!");
        }
        sqlSession.close();
    }

我又把大数据改为数据库了,有点强迫症,结果如下:

所有的项目文件结构如下所示:

相关文章
|
1月前
|
SQL 缓存 Java
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
本文详细介绍了MyBatis的各种常见用法MyBatis多级缓存、逆向工程、分页插件 包括获取参数值和结果的各种情况、自定义映射resultMap、动态SQL
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
|
6月前
|
SQL 分布式计算 DataWorks
DataWorks操作报错合集之SQL错误[0A000],通常是什么造成的
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
64 1
|
1月前
|
SQL Java 数据库连接
canal-starter 监听解析 storeValue 不一样,同样的sql 一个在mybatis执行 一个在数据库操作,导致解析不出正确对象
canal-starter 监听解析 storeValue 不一样,同样的sql 一个在mybatis执行 一个在数据库操作,导致解析不出正确对象
|
2月前
|
SQL Java 数据库连接
mybatis如何实现分页查询?
【10月更文挑战第19天】mybatis如何实现分页查询?
152 3
|
2月前
|
SQL Java 数据库连接
mybatis使用四:dao接口参数与mapper 接口中SQL的对应和对应方式的总结,MyBatis的parameterType传入参数类型
这篇文章是关于MyBatis中DAO接口参数与Mapper接口中SQL的对应关系,以及如何使用parameterType传入参数类型的详细总结。
59 10
|
3月前
|
SQL XML Java
mybatis复习03,动态SQL,if,choose,where,set,trim标签及foreach标签的用法
文章介绍了MyBatis中动态SQL的用法,包括if、choose、where、set和trim标签,以及foreach标签的详细使用。通过实际代码示例,展示了如何根据条件动态构建查询、更新和批量插入操作的SQL语句。
mybatis复习03,动态SQL,if,choose,where,set,trim标签及foreach标签的用法
|
3月前
|
SQL XML Java
mybatis :sqlmapconfig.xml配置 ++++Mapper XML 文件(sql/insert/delete/update/select)(增删改查)用法
当然,这些仅是MyBatis功能的初步介绍。MyBatis还提供了高级特性,如动态SQL、类型处理器、插件等,可以进一步提供对数据库交互的强大支持和灵活性。希望上述内容对您理解MyBatis的基本操作有所帮助。在实际使用中,您可能还需要根据具体的业务要求调整和优化SQL语句和配置。
70 1
|
5月前
|
SQL 分布式计算 MaxCompute
SQL开发问题之对于ODPS中的UNION操作,执行计划的问题如何解决
SQL开发问题之对于ODPS中的UNION操作,执行计划的问题如何解决
|
5月前
|
SQL Java 数据库连接
idea中配置mybatis 映射文件模版及 mybatis plus 自定义sql
idea中配置mybatis 映射文件模版及 mybatis plus 自定义sql
119 3
|
5月前
|
SQL 分布式计算 DataWorks
MaxCompute操作报错合集之使用sql查询一个表的分区数据时遇到报错,该如何解决
MaxCompute是阿里云提供的大规模离线数据处理服务,用于大数据分析、挖掘和报表生成等场景。在使用MaxCompute进行数据处理时,可能会遇到各种操作报错。以下是一些常见的MaxCompute操作报错及其可能的原因与解决措施的合集。