当前位置: 代码网 > it编程>编程语言>Java > 使用MyBatis的动态SQL注解实现实体的CRUD操作代码

使用MyBatis的动态SQL注解实现实体的CRUD操作代码

2024年07月05日 Java 我要评论
1. 引言在使用mybatis进行数据库操作时,动态sql注解提供了一种优雅的方式来编写动态sql语句。mybatis 3.x 版本提供了以下四个crud的高级注解:@selectprovider:用

1. 引言

在使用mybatis进行数据库操作时,动态sql注解提供了一种优雅的方式来编写动态sql语句。mybatis 3.x 版本提供了以下四个crud的高级注解:

  • @selectprovider:用于构建动态查询sql。
  • @insertprovider:用于构建动态新增sql。
  • @updateprovider:用于构建动态更新sql。
  • @deleteprovider:用于构建动态删除sql。

这些注解可以帮助开发者在mapper接口中动态地构建sql语句,避免了在xml配置文件中编写大量的sql代码,使代码更加简洁和易于维护。本文将详细介绍如何使用这些动态sql注解来实现书籍信息的查询、新增、修改和删除操作。

此外,我们将与mybatis plus中的@select注解进行对比,展示mybatis动态sql注解的优势和灵活性。

2. 准备工作

2.1 创建数据表

首先,需要创建一个代表书籍信息的表 tb_book

-- 判断数据表是否存在,存在则删除
drop table if exists tb_book;

-- 创建“书籍信息”数据表
create table if not exists tb_book
(
    book_id int auto_increment primary key comment '书籍编号',
    book_name varchar(50) not null comment '书名',
    author varchar(50) not null comment '作者',
    publisher varchar(50) comment '出版社',
    publish_date date comment '出版日期'
) comment = '书籍信息表';

-- 添加数据
insert into tb_book(book_name, author, publisher, publish_date) values ('书籍1', '作者1', '出版社1', '2023-01-01');

2.2 创建实体类 book

在 com.zhouquan.entity 包中创建 book 类,使用 @data 注解来自动生成getter和setter方法。

package com.zhouquan.entity;
import lombok.data;
import java.util.date;

/**
 * 书籍信息实体类
 */
@data
public class book {
    /**
     * 书籍编号
     */
    private int bookid;
    
    /**
     * 书名
     */
    private string bookname;
    
    /**
     * 作者
     */
    private string author;
    
    /**
     * 出版社
     */
    private string publisher;
    
    /**
     * 出版日期
     */
    private date publishdate;
}

2.3 修改mapper接口 bookmapper

在 com.zhouquan.mapper 包中创建 bookmapper 接口,并使用动态sql注解来实现crud操作。

package com.zhouquan.mapper;

import com.zhouquan.entity.book;
import org.apache.ibatis.annotations.*;
import org.apache.ibatis.jdbc.sql;
import org.springframework.stereotype.repository;

@mapper
@repository
public interface bookmapper {

    @selectprovider(type = booksqlbuilder.class, method = "buildgetbookbyidsql")
    public book getbookbyid(@param("bookid") int bookid);

    @insertprovider(type = booksqlbuilder.class, method = "buildinsertbooksql")
    @options(usegeneratedkeys = true, keycolumn = "book_id", keyproperty = "bookid")
    public int insertbook(book book);

    @updateprovider(type = booksqlbuilder.class, method = "buildupdatebooksql")
    public int updatebook(book book);

    @deleteprovider(type = booksqlbuilder.class, method = "builddeletebooksql")
    public int deletebook(@param("bookid") int bookid);

    class booksqlbuilder {
        public string buildgetbookbyidsql(@param("bookid") int bookid) {
            return new sql() {{
                select("*");
                from("tb_book");
                where("book_id = #{bookid}");
            }}.tostring();
        }

        public string buildinsertbooksql(book book) {
            return new sql() {{
                insert_into("tb_book");
                values("book_name", "#{bookname}");
                values("author", "#{author}");
                values("publisher", "#{publisher}");
                values("publish_date", "#{publishdate}");
            }}.tostring();
        }

        public string buildupdatebooksql(book book) {
            return new sql() {{
                update("tb_book");
                set("book_name = #{bookname}", "author = #{author}", "publisher = #{publisher}", "publish_date = #{publishdate}");
                where("book_id = #{bookid}");
            }}.tostring();
        }

        public string builddeletebooksql(@param("bookid") int bookid) {
            return new sql() {{
                delete_from("tb_book");
                where("book_id = #{bookid}");
            }}.tostring();
        }
    }
}

3. 测试crud操作

为了测试crud操作,我们将使用junit进行单元测试,并通过日志记录操作的结果。

3.1 配置日志

在maven的pom.xml文件中引入slf4j和logback的依赖:

<dependencies>
    <!-- mybatis 依赖 -->
    <dependency>
        <groupid>org.mybatis.spring.boot</groupid>
        <artifactid>mybatis-spring-boot-starter</artifactid>
        <version>2.1.4</version>
    </dependency>
    
    <!-- slf4j 依赖 -->
    <dependency>
        <groupid>org.slf4j</groupid>
        <artifactid>slf4j-api</artifactid>
        <version>1.7.30</version>
    </dependency>
  
</dependencies>

3.2 查询操作

import com.zhouquan.entity.book;
import com.zhouquan.mapper.bookmapper;
import org.junit.jupiter.api.test;
import org.springframework.beans.factory.annotation.autowired;
import org.slf4j.logger;
import org.slf4j.loggerfactory;

public class bookmappertest {

    private static final logger logger = loggerfactory.getlogger(bookmappertest.class);

    @autowired
    private bookmapper bookmapper;

    /**
     * 根据书籍id,获取书籍信息
     */
    @test
    public void getbookbyid() {
        book book = bookmapper.getbookbyid(1);
        logger.info("书籍编号:{}", book.getbookid());
        logger.info("书名:{}", book.getbookname());
        logger.info("作者:{}", book.getauthor());
        logger.info("出版社:{}", book.getpublisher());
        logger.info("出版日期:{}", book.getpublishdate());
    }
}

3.3 新增操作

@autowired
private bookmapper bookmapper;

/**
 * 新增书籍,并获取自增主键
 */
@test
public void insertbook() {
    book book = new book();
    book.setbookname("新书");
    book.setauthor("新作者");
    book.setpublisher("新出版社");
    book.setpublishdate(new date());
    bookmapper.insertbook(book);
    logger.info("新增书籍id:{}", book.getbookid());
}

3.4 修改操作

@autowired
private bookmapper bookmapper;

/**
 * 更新书籍信息
 */
@test
public void updatebook() {
    book book = bookmapper.getbookbyid(1);
    book.setbookname("更新后的书名");
    bookmapper.updatebook(book);
    logger.info("更新后的书名:{}", book.getbookname());
}

3.5 删除操作

@autowired
private bookmapper bookmapper;

/**
 * 删除书籍
 */
@test
public void deletebook() {
    bookmapper.deletebook(1);
    logger.info("删除书籍id为1的记录");
}

4. 与mybatis plus的对比

mybatis plus提供了一种更加简洁的方式来编写sql语句,例如,使用@select注解可以直接在mapper接口中编写sql语句,而无需单独定义sql构建器类。

例如,使用mybatis plus可以这样定义bookmapper接口:

import com.baomidou.mybatisplus.core.mapper.basemapper;
import com.zhouquan.entity.book;
import org.apache.ibatis.annotations.select;

public interface bookmapper extends basemapper<book> {

    @select("select * from tb_book where book_id = #{bookid}")
    book getbookbyid(int bookid);
}

这种方式相对于mybatis动态sql注解而言,更加直接和易读。但是,mybatis动态sql注解在处理复杂sql语句时具有更高的灵活性和可维护性,特别是当需要根据不同条件动态生成sql时,mybatis动态sql注解显得更为强大和适用

5. 动态sql注解的适用场景

5.1 动态查询条件

在一些应用中,查询条件是动态的,可能根据不同的用户输入或业务逻辑生成不同的查询条件。使用动态sql注解可以在运行时根据这些条件动态构建查询语句,避免了硬编码查询条件的问题。

public string builddynamicquerysql(map<string, object> params) {
    return new sql() {{
        select("*");
        from("tb_book");
        if (params.get("author") != null) {
            where("author = #{author}");
        }
        if (params.get("publisher") != null) {
            where("publisher = #{publisher}");
        }
        if (params.get("publishdate") != null) {
            where("publish_date = #{publishdate}");
        }
    }}.tostring();
}

5.2 动态插入和更新

在一些情况下,插入或更新的数据字段可能不是固定的,而是根据业务需求动态变化的。使用动态sql注解可以根据传入的实体对象构建动态插入或更新语句。

public string builddynamicinsertsql(book book) {
    return new sql() {{
        insert_into("tb_book");
        if (book.getbookname() != null) {
            values("book_name", "#{bookname}");
        }
        if (book.getauthor() != null) {
            values("author", "#{author}");
        }
        if (book.getpublisher() != null) {
            values("publisher", "#{publisher}");
        }
        if (book.getpublishdate() != null) {
            values("publish_date", "#{publishdate}");
        }
    }}.tostring();
}

public string builddynamicupdatesql(book book) {
    return new sql() {{
        update("tb_book");
        if (book.getbookname() != null) {
            set("book_name = #{bookname}");
        }
        if (book.getauthor() != null) {
            set("author = #{author}");
        }
        if (book.getpublisher() != null) {
            set("publisher = #{publisher}");
        }
        if (book.getpublishdate() != null) {
            set("publish_date = #{publishdate}");
        }
        where("book_id = #{bookid}");
    }}.tostring();
}

5.3 复杂的业务逻辑

在一些复杂的业务场景中,sql语句的构建逻辑可能非常复杂,涉及多个表的联接、多种条件的判断等。使用动态sql注解可以在java代码中使用条件逻辑来构建复杂的sql语句,使代码更加清晰和易于维护。

public string buildcomplexquerysql(book book) {
    return new sql() {{
        select("b.*, a.author_name, p.publisher_name");
        from("tb_book b");
        join("tb_author a on b.author_id = a.author_id");
        join("tb_publisher p on b.publisher_id = p.publisher_id");
        if (book.getbookname() != null) {
            where("b.book_name like concat('%', #{bookname}, '%')");
        }
        if (book.getauthor() != null) {
            where("a.author_name like concat('%', #{author}, '%')");
        }
        if (book.getpublisher() != null) {
            where("p.publisher_name like concat('%', #{publisher}, '%')");
        }
    }}.tostring();
}

5.4 查询结果动态列的聚合

需求类似于下,根据专题聚合出不同的资料类型,select中的列需要动态的拼接,显然mp的mapper对于此种需求的支持并不友好

 /**
     * 资源量统计-根据专题
     * 之所以使用此种方式是因为统计的列是不固定的,所以需要动态拼接select
     *
     * @param resourcetypenamelist 资源名称列表
     * @param resourcetypesidlist  资源sid列表
     * @param start                加工开始时间
     * @param end                  加工结束时间
     * @return
     */
    public string grouptopicdynamicsql(final list<string> resourcetypenamelist, final list<string> resourcetypesidlist,
                                       final localdate start, final localdate end) {
        // 构建外部查询
        sql outerquery = new sql();
        outerquery.select("coalesce(topic_name, '总计') as '专题'");

        if (resourcetypenamelist != null && !resourcetypenamelist.isempty()) {
            for (string rt : resourcetypenamelist) {
                outerquery.select(string.format("sum(case when resource_type_name = '%s' then count else 0 end) as " +
                        "'%s'", rt, rt));
            }
        }

        // 构建子查询
        sql subquery = new sql();
        subquery.select("rt.name as resource_type_name, t.name as topic_name, count(*) as count")
                .from("works w")
                .join("works_topic wt on w.sid = wt.work_sid")
                .join("topic t on wt.topic_sid = t.sid")
                .join("resource_type rt on w.type_leaf_sid = rt.sid")
                .where(" w.deleted=0 ");

        if (resourcetypenamelist != null && !resourcetypenamelist.isempty()) {
            string joinedresourcetypes = resourcetypesidlist.stream()
                    .map(rt -> "'" + rt + "'")
                    .collect(collectors.joining(", "));
            subquery.where("w.type_leaf_sid in (" + joinedresourcetypes + ")");
        }
        if (start != null) {
            subquery.where("w.update_time >= #{start}");
        }
        if (end != null) {
            subquery.where("w.update_time <= #{end}");
        }
        subquery.group_by("rt.name, t.name");

        outerquery.select("sum(count) as '总计'")
                .from("(" + subquery + ") as subquery")
                .group_by("topic_name with rollup");

        return outerquery.tostring();
    }
/**
 * 统计分析-资源量统计
 *
 * @param resourcetypenamelist
 * @param resourcetypesidlist
 * @param start
 * @param end
 * @return
 */
@selectprovider(type = workssqlprovider.class, method = "grouptopicdynamicsql")
list<map<string, object>> staticbytopic(@param("resourcetypenamelist") list<string> resourcetypenamelist,
                                        @param("resourcetypesidlist") list<string> resourcetypesidlist,
                                        @param("start") localdate start,
                                        @param("end") localdate end);

6. 小结

mybatis动态sql注解通过提供更加灵活和动态的方式来构建sql语句,使得代码更加简洁和易于维护。而mybatis plus通过简化sql编写过程,提供了一种更加便捷的方式来进行数据库操作。根据具体项目的需求和复杂度,可以选择适合的工具来实现数据库操作。

通过上述介绍,可以看出动态sql注解在处理动态查询条件、动态插入和更新以及复杂的业务逻辑时具有明显的优势和适用性。在实际开发中,合理使用动态sql注解可以提高代码的灵活性和可维护性。

以上就是使用mybatis的动态sql注解实现实体的crud操作代码的详细内容,更多关于mybatis动态sqlcrud操作的资料请关注代码网其它相关文章!

(0)

相关文章:

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

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com