欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

使用MyBatis的動態(tài)SQL注解實(shí)現(xiàn)實(shí)體的CRUD操作代碼

 更新時間:2024年06月24日 09:00:41   作者:徐州蔡徐坤  
在使用MyBatis進(jìn)行數(shù)據(jù)庫操作時,動態(tài)SQL注解提供了一種優(yōu)雅的方式來編寫動態(tài)SQL語句,MyBatis?3.x?版本提供了下四個CRUD的高級注解,這些注解可以幫助開發(fā)者在Mapper接口中動態(tài)地構(gòu)建SQL語句,本文給大家介紹了使用MyBatis的動態(tài)SQL注解實(shí)現(xiàn)實(shí)體的CRUD操作

1. 引言

在使用MyBatis進(jìn)行數(shù)據(jù)庫操作時,動態(tài)SQL注解提供了一種優(yōu)雅的方式來編寫動態(tài)SQL語句。MyBatis 3.x 版本提供了以下四個CRUD的高級注解:

  • @SelectProvider:用于構(gòu)建動態(tài)查詢SQL。
  • @InsertProvider:用于構(gòu)建動態(tài)新增SQL。
  • @UpdateProvider:用于構(gòu)建動態(tài)更新SQL。
  • @DeleteProvider:用于構(gòu)建動態(tài)刪除SQL。

這些注解可以幫助開發(fā)者在Mapper接口中動態(tài)地構(gòu)建SQL語句,避免了在XML配置文件中編寫大量的SQL代碼,使代碼更加簡潔和易于維護(hù)。本文將詳細(xì)介紹如何使用這些動態(tài)SQL注解來實(shí)現(xiàn)書籍信息的查詢、新增、修改和刪除操作。

此外,我們將與MyBatis Plus中的@Select注解進(jìn)行對比,展示MyBatis動態(tài)SQL注解的優(yōu)勢和靈活性。

2. 準(zhǔn)備工作

2.1 創(chuàng)建數(shù)據(jù)表

首先,需要創(chuàng)建一個代表書籍信息的表 tb_book。

-- 判斷數(shù)據(jù)表是否存在,存在則刪除
DROP TABLE IF EXISTS tb_book;

-- 創(chuàng)建“書籍信息”數(shù)據(jù)表
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 = '書籍信息表';

-- 添加數(shù)據(jù)
INSERT INTO tb_book(book_name, author, publisher, publish_date) VALUES ('書籍1', '作者1', '出版社1', '2023-01-01');

2.2 創(chuàng)建實(shí)體類 Book

在 com.zhouquan.entity 包中創(chuàng)建 Book 類,使用 @Data 注解來自動生成getter和setter方法。

package com.zhouquan.entity;
import lombok.Data;
import java.util.Date;

/**
 * 書籍信息實(shí)體類
 */
@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 包中創(chuàng)建 BookMapper 接口,并使用動態(tài)SQL注解來實(shí)現(xiàn)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進(jìn)行單元測試,并通過日志記錄操作的結(jié)果。

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;

    /**
     * 根據(jù)書籍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語句,而無需單獨(dú)定義SQL構(gòu)建器類。

例如,使用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動態(tài)SQL注解而言,更加直接和易讀。但是,MyBatis動態(tài)SQL注解在處理復(fù)雜SQL語句時具有更高的靈活性和可維護(hù)性,特別是當(dāng)需要根據(jù)不同條件動態(tài)生成SQL時,MyBatis動態(tài)SQL注解顯得更為強(qiáng)大和適用

5. 動態(tài)SQL注解的適用場景

5.1 動態(tài)查詢條件

在一些應(yīng)用中,查詢條件是動態(tài)的,可能根據(jù)不同的用戶輸入或業(yè)務(wù)邏輯生成不同的查詢條件。使用動態(tài)SQL注解可以在運(yùn)行時根據(jù)這些條件動態(tài)構(gòu)建查詢語句,避免了硬編碼查詢條件的問題。

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 動態(tài)插入和更新

在一些情況下,插入或更新的數(shù)據(jù)字段可能不是固定的,而是根據(jù)業(yè)務(wù)需求動態(tài)變化的。使用動態(tài)SQL注解可以根據(jù)傳入的實(shí)體對象構(gòu)建動態(tài)插入或更新語句。

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 復(fù)雜的業(yè)務(wù)邏輯

在一些復(fù)雜的業(yè)務(wù)場景中,SQL語句的構(gòu)建邏輯可能非常復(fù)雜,涉及多個表的聯(lián)接、多種條件的判斷等。使用動態(tài)SQL注解可以在Java代碼中使用條件邏輯來構(gòu)建復(fù)雜的SQL語句,使代碼更加清晰和易于維護(hù)。

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 查詢結(jié)果動態(tài)列的聚合

需求類似于下,根據(jù)專題聚合出不同的資料類型,select中的列需要動態(tài)的拼接,顯然MP的mapper對于此種需求的支持并不友好

 /**
     * 資源量統(tǒng)計(jì)-根據(jù)專題
     * 之所以使用此種方式是因?yàn)榻y(tǒng)計(jì)的列是不固定的,所以需要動態(tài)拼接select
     *
     * @param resourceTypeNameList 資源名稱列表
     * @param resourceTypeSidList  資源sid列表
     * @param start                加工開始時間
     * @param end                  加工結(jié)束時間
     * @return
     */
    public String groupTopicDynamicSQL(final List<String> resourceTypeNameList, final List<String> resourceTypeSidList,
                                       final LocalDate start, final LocalDate end) {
        // 構(gòu)建外部查詢
        SQL outerQuery = new SQL();
        outerQuery.SELECT("COALESCE(topic_name, '總計(jì)') 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));
            }
        }

        // 構(gòu)建子查詢
        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 '總計(jì)'")
                .FROM("(" + subQuery + ") AS subQuery")
                .GROUP_BY("topic_name WITH ROLLUP");

        return outerQuery.toString();
    }
/**
 * 統(tǒng)計(jì)分析-資源量統(tǒng)計(jì)
 *
 * @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. 小結(jié)

MyBatis動態(tài)SQL注解通過提供更加靈活和動態(tài)的方式來構(gòu)建SQL語句,使得代碼更加簡潔和易于維護(hù)。而MyBatis Plus通過簡化SQL編寫過程,提供了一種更加便捷的方式來進(jìn)行數(shù)據(jù)庫操作。根據(jù)具體項(xiàng)目的需求和復(fù)雜度,可以選擇適合的工具來實(shí)現(xiàn)數(shù)據(jù)庫操作。

通過上述介紹,可以看出動態(tài)SQL注解在處理動態(tài)查詢條件、動態(tài)插入和更新以及復(fù)雜的業(yè)務(wù)邏輯時具有明顯的優(yōu)勢和適用性。在實(shí)際開發(fā)中,合理使用動態(tài)SQL注解可以提高代碼的靈活性和可維護(hù)性。

以上就是使用MyBatis的動態(tài)SQL注解實(shí)現(xiàn)實(shí)體的CRUD操作代碼的詳細(xì)內(nèi)容,更多關(guān)于MyBatis動態(tài)SQLCRUD操作的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論