MyBatisPlus筆記

来源:https://www.cnblogs.com/LoginX/archive/2022/10/11/Login_X55.html
-Advertisement-
Play Games

MyBatisPlus 快速入門 1.創建資料庫mybatisplus 2.創建user表並插入數據 DROP TABLE IF EXISTS user; CREATE TABLE user ( id BIGINT(20) NOT NULL COMMENT '主鍵ID', name VARCHAR( ...


MyBatisPlus

快速入門

1.創建資料庫mybatisplus
2.創建user表並插入數據
DROP TABLE IF EXISTS user; 
CREATE TABLE user 
( 
    id BIGINT(20) NOT NULL COMMENT '主鍵ID', 
    name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名', 
    age INT(11) NULL DEFAULT NULL COMMENT '年齡', 
    email VARCHAR(50) NULL DEFAULT NULL COMMENT '郵箱', 
    PRIMARY KEY (id) 
);
INSERT INTO user (id, name, age, email) VALUES 
(1, 'Jone', 18, '[email protected]'), 
(2, 'Jack', 20, '[email protected]'), 
(3, 'Tom', 28, '[email protected]'), 
(4, 'Sandy', 21, '[email protected]'), 
(5, 'Billie', 24, '[email protected]');
-- 真實開發中一般還需要version(樂觀鎖)、deleted(邏輯刪除)、gmt_create、gmt_modified
3.初始化SpringBoot項目
4.導入依賴

儘量不要同時導入mybatis和mybatisplus的依賴

<!-- 資料庫驅動 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
<!-- mybatis-plus-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.0.5</version>
</dependency>
5.連接資料庫

application.properties

# mysql 5 驅動不同 com.mysql.jdbc.Driver
# mysql 8 驅動不同com.mysql.cj.jdbc.Driver、需要增加時區的配置serverTimezone=GMT%2B8 
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus? useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

6.傳統方式pojo-dao(連接mybatis,配置mapper.xml文件)-service-controller

6.使用MyBatisPlus
  • pojo
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
  • mapper介面
@Repository//持久層
public interface UserMapper extends BaseMapper<User> {
}
  • 測試類

首先在主類中配置mapper掃描@MapperScan("com.xust.mapper")

@SpringBootTest
class MybatisPlusApplicationTests {

    @Autowired
    private UserMapper userMapper;

    @Test
    void contextLoads() {
        //參數是一個Wrapper,條件構造器,這裡先不用
        List<User> users=userMapper.selectList(null);
        users.forEach(System.out::println);
    }
}

配置日誌

在開發中使用,通過日誌查看sql如何執行

applicatiohn.properties

mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

CRUD擴展

插入

@SpringBootTest
class MybatisPlusApplicationTests {
	// 測試插入
    @Test
    public void testInsert() {
        User user = new User();
        user.setName("xust");
        user.setAge(3);
        user.setEmail("[email protected]");
        int result = userMapper.insert(user); // 幫我們自動生成id
        System.out.println(result); // 受影響的行數
        System.out.println(user); // 發現,id會自動回填
    }
}

更新

@SpringBootTest
class MybatisPlusApplicationTests {

    @Autowired
    private UserMapper userMapper;

    //測試更新
    @Test
    public void testUpdate(){
        User user = new User();
        user.setId(1L);
        user.setName("xxx");
        userMapper.updateById(user);
    }
}

自動填充

創建時間、修改時間!這些個操作一遍都是自動化完成的,我們不希望手動更新

我這裡使用的是SQLyog

資料庫級別操作

img

代碼級別操作

1.首先恢復清除資料庫中預設值和更新效果

2.實體類欄位屬性上需要增加註解

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    @TableId(type = IdType.INPUT)      //一旦手動輸入id後就需要自己配置id了
    private Long id;
    private String name;
    private Integer age;
    private String email;

    @TableField(fill= FieldFill.INSERT)     //插入時自動填充
    private Date createTime;
    @TableField(fill= FieldFill.INSERT_UPDATE)      //插入和更新時自動填充
    private Date updateTime;
}

3.編寫處理器來處理這個註解

@Slf4j
@Component  //將處理器加入到IOC容器中
public class MyMetaObjectHandler implements MetaObjectHandler {
    //插入時的填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill...........");
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }

    //更新時的填充策略
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill...........");
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}

樂觀鎖

意圖:

當更新一條數據時,希望這條數據沒有被其他人更新。

  • 樂觀鎖:它總是認為不會出現問題,無論乾什麼不去上鎖!如果出現了問題,再次更新值測試
  • 悲觀鎖:它總是認為總是出現問題,無論乾什麼都會上鎖!再去操作

樂觀鎖實現方式:

  1. 取出記錄時,獲取當前version
  2. 更新時帶上version
  3. 執行更新時,set version=newVersion where version=oldVersion
  4. 如果version不對,就更新失敗
樂觀鎖:1、先查詢,獲得版本號 version = 1 
-- A 
update user set name = "kuangshen", version = version + 1 
where id = 2 and version = 1 
-- B 線程搶先完成,這個時候 version = 2,會導致 A 修改失敗! 
update user set name = "kuangshen", version = version + 1 
where id = 2 and version = 1

測試

1. 資料庫添加version欄位

img2

2.實體類加對應欄位
@Version //樂觀鎖Version註解
private Integer version;
3.註冊組件
@EnableTransactionManagement
@Configuration // 配置類 
public class MyBatisPlusConfig { // 註冊樂觀鎖插件 
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }
}
4.測試
@SpringBootTest
class MybatisPlusApplicationTests {

    @Autowired
    private UserMapper userMapper;

    //測試樂觀鎖成功
    @Test
    public void testOptimisticLocker(){
        //查詢用戶信息
        User user = userMapper.selectById(1L);
        //修改用戶信息
        user.setName("yyy");
        user.setEmail("[email protected]");
        //執行更新操作
        userMapper.updateById(user);
    }

    //測試樂觀鎖失敗
    @Test
    public void testOptimisticLocker2(){
        //A
        User user = userMapper.selectById(1L);
        user.setName("yyy1");
        user.setEmail("[email protected]");

        //B,模擬另外一個線程執行了插隊操作
        User user2 = userMapper.selectById(1L);
        user2.setName("yyy2");
        user2.setEmail("[email protected]");

        //B執行更新
        userMapper.updateById(user2);
        //A執行更新,如果沒有樂觀鎖就會更新
        userMapper.updateById(user);
    }
}

查詢操作

@SpringBootTest
class MybatisPlusApplicationTests {

    @Autowired
    private UserMapper userMapper;

    // 測試查詢
    @Test
    public void testSelectById() {
        User user = userMapper.selectById(1L);
        System.out.println(user);
    }

    // 測試批量查詢!
    @Test
    public void testSelectByBatchId() {
        List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
        users.forEach(System.out::println);
    }

    // 按條件查詢之使用map操作
    @Test
    public void testSelectByBatchIds() {
        HashMap<String, Object> map = new HashMap<>();
        // 自定義要查詢
        map.put("name", "ccc");
        map.put("age", 3);
        List<User> users = userMapper.selectByMap(map);
        users.forEach(System.out::println);
    }
}

分頁查詢

1.配置攔截器組件

MyBatisPlusConfig.java

@Bean
public PaginationInterceptor paginationInterceptor() {
    return new PaginationInterceptor();
}
2.直接使用Page對象
@SpringBootTest
class MybatisPlusApplicationTests {

    @Autowired
    private UserMapper userMapper;

    //測試分頁查詢
    @Test
    public void testPage(){
        //參數一:當前頁
        //參數二:顯示條數
        Page<User> page=new Page<>(1,3);
        userMapper.selectPage(page,null);

        //列印當前頁
        page.getRecords().forEach(System.out::println);
        //列印總數
        System.out.println(page.getTotal());
    }
}

刪除操作

根據id刪除

@SpringBootTest
class MybatisPlusApplicationTests {

    @Autowired
    private UserMapper userMapper;

    //測試刪除
    @Test
    public void testDeleteById() {
        userMapper.deleteById(1579436224978829314L);
    }

    //批量刪除
    @Test
    public void testDeleteBatchId() {
        userMapper.deleteBatchIds(Arrays.asList(1579459015811768322L, 1579459015811768324L));
    }

    //條件刪除map操作
    @Test
    public void testDeleteMap() {
        HashMap<String, Object> map = new HashMap<>();
        map.put("name", "ccc");
        userMapper.deleteByMap(map);
    }
}

邏輯刪除

物理刪除:從資料庫中直接移除

邏輯刪除:在資料庫中沒有直接移除,通過一個變數使其失效

1.在資料庫表中增加一個deleted欄位,為0表示沒刪

img3

2.實體類中增加屬性

@TableLogic //邏輯刪除
private Integer deleted;

3.配置

MyBatisPlusConfig.java

// 邏輯刪除組件! 
@Bean
public ISqlInjector sqlInjector() {
    return new LogicSqlInjector();
}

application.properties

# 配置邏輯刪除
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0

4.測試

執行之前的刪除操作,實際上進行的是update操作

性能分析插件

平時開發時會遇到一些慢SQL

作用:性能分析攔截器,用於輸出每條 SQL 語句及其執行時間

在測試和開發環境下使用

1.設置開發環境

application.properties

spring.profiles.active=dev

2.導入插件

MyBatisPlusConfig.java

@Bean
@Profile({"dev","test"})    //設置在dev、test環境開啟,保證效率
public PerformanceInterceptor performanceInterceptor(){
    PerformanceInterceptor performanceInterceptor=new PerformanceInterceptor();
    performanceInterceptor.setMaxTime(100);    //設置SQL執行的最大時間,超過則不執行
    performanceInterceptor.setFormat(true); //是否開啟格式化,讓SQL查看起來更方便
    return performanceInterceptor;
}

條件構造器(Wrapper)

比較重要,寫複雜的SQL可以用它來代替

@SpringBootTest
public class WrapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    void contextLoads() {
        //查詢name不為空,email不為空,且年齡大於等於12的
        QueryWrapper<User> wrapper=new QueryWrapper<>();
        wrapper.isNotNull("name")
                .isNotNull("email")
                .ge("age",12);

        userMapper.selectList(wrapper);
    }
    @Test
    void test2() {
        //查詢name為Tom的
        QueryWrapper<User> wrapper=new QueryWrapper<>();
        wrapper.eq("name","Tom");
        User user = userMapper.selectOne(wrapper);
        System.out.println(user);
    }
    @Test
    void test3() {
        //查詢年齡20~30的人
        QueryWrapper<User> wrapper=new QueryWrapper<>();
        wrapper.between("age",20,30);
        Integer count= userMapper.selectCount(wrapper);//查詢結果數
        System.out.println(count);
    }
    //模糊查詢
    @Test
    void test4() {
        //name中不包含o,且email以t開頭
        QueryWrapper<User> wrapper=new QueryWrapper<>();
        wrapper.notLike("name","o")
                .likeRight("email","t");    //相當於t%
        List<Map<String, Object>> maps= userMapper.selectMaps(wrapper);
        maps.forEach(System.out::println);
    }
    @Test
    void test5() {
        QueryWrapper<User> wrapper=new QueryWrapper<>();
        //id在子查詢中查出來
        wrapper.inSql("id","select id from user where id<3");
        List<Object> objects = userMapper.selectObjs(wrapper);
        objects.forEach(System.out::println);
    }
    @Test
    void test6() {
        QueryWrapper<User> wrapper=new QueryWrapper<>();
        //通過id進行排序
        wrapper.orderByDesc("id");

        List<User> list = userMapper.selectList(wrapper);
        list.forEach(System.out::println);
    }
}

代碼生成器

1.引入相關依賴,配置好資料庫

2.寫生成器

package com.xust;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

import java.util.ArrayList;

/**
 * @Description: 代碼生成器
 * @Author: XiePengXiong
 * @Date: 2022/10/11 19:46
 */
public class generator {
    public static void main(String[] args) {
        //構建代碼生成器對象
        AutoGenerator mpg = new AutoGenerator();

        //配置策略
        //1.全局配置************************************************************************************************************
        GlobalConfig gc = new GlobalConfig();   //generator包下的
        String projectPath = System.getProperty("user.dir");    //獲取當前項目路徑
        gc.setOutputDir(projectPath + "/src/main/java");  //輸出目錄
        gc.setAuthor("xpx");    //作者
        gc.setOpen(false);  //生成後是否打開資源管理器(文件夾)
        gc.setFileOverride(false);  //是否覆蓋上次生成的
        gc.setServiceName("%sService"); //去Service的I首碼
        gc.setIdType(IdType.ID_WORKER); //生成策略
        gc.setDateType(DateType.ONLY_DATE); //日期類型
        gc.setSwagger2(true);   //Swagger
        mpg.setGlobalConfig(gc);    //將全局配置放入生成器中

        //2.設置數據源************************************************************************************************************
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/kuang_community? useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("xpx24167830");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        //3、包的配置************************************************************************************************************
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("blog");
        pc.setParent("com.xust");
        pc.setEntity("pojo");
        pc.setMapper("mapper");
        pc.setService("service");
        pc.setController("controller");
        mpg.setPackageInfo(pc);

        //4、策略配置************************************************************************************************************
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("blog_tags", "course", "links", "sys_settings", "user_record", " user_say"); // 設置要映射的表名
        strategy.setNaming(NamingStrategy.underline_to_camel);  //下劃線轉駝峰命名
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);    //下劃線轉駝峰命名
        strategy.setEntityLombokModel(true); // 自動lombok;
        strategy.setLogicDeleteFieldName("deleted"); // 邏輯刪除
        // 自動填充配置
        TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT);    //創建時間
        TableFill gmtModified = new TableFill("gmt_modified", FieldFill.INSERT_UPDATE); //修改時間
        ArrayList<TableFill> tableFills = new ArrayList<>();
        tableFills.add(gmtCreate);
        tableFills.add(gmtModified);
        strategy.setTableFillList(tableFills);
        // 樂觀鎖
        strategy.setVersionFieldName("version");
        strategy.setRestControllerStyle(true);  //開啟駝峰命名
        strategy.setControllerMappingHyphenStyle(true); // url轉換成下劃線localhost:8080/hello_id_2
        mpg.setStrategy(strategy);

        //執行
        mpg.execute();
    }
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Optional 類是一個可以為null的容器對象。如果值存在則isPresent()方法會返回true,調用get()方法會返回該對象。 ...
  • 什麼是阻塞隊列 【1】阻塞隊列:從定義上來說是隊列的一種,那麼肯定是一個先進先出(FIFO)的數據結構。與普通隊列不同的是,它支持兩個附加操作,即阻塞添加和阻塞刪除方法。 【2】阻塞添加:當阻塞隊列是滿時,往隊列里添加元素的操作將被阻塞。 【3】阻塞移除:當阻塞隊列是空時,從隊列中獲取元素/刪除元素 ...
  • LinkedBlockingDeque介紹 【1】LinkedBlockingDeque是一個基於鏈表實現的雙向阻塞隊列,預設情況下,該阻塞隊列的大小為Integer.MAX_VALUE,可以看做無界隊列,但也可以設置容量限制,作為有界隊列。 【2】相比於其他阻塞隊列,LinkedBlockingD ...
  • 羅馬數字包含以下七種字元: I, V, X, L,C,D 和 M。 字元 數值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如, 羅馬數字 2 寫做 II ,即為兩個併列的 1 。12 寫做 XII ,即為 X + II 。 27 寫做 XXVII, 即為 XX + ...
  • LinkedBlockingQueue介紹 【1】LinkedBlockingQueue是一個基於鏈表實現的阻塞隊列,預設情況下,該阻塞隊列的大小為Integer.MAX_VALUE,由於這個數值特別大,所以 LinkedBlockingQueue 也被稱作無界隊列,代表它幾乎沒有界限,隊列可以隨著 ...
  • 演算法步驟 遍歷整個數組,找到最小(大)的元素,放到數組的起始位置。 再遍歷剩下的數組,找到剩下元素中的最小(大)元素,放到數組的第二個位置。 重覆以上步驟,直到排序完成。 一共需要遍曆數組元素個數-1次,當找到第二大(小)的元素時,可以停止。這時最後一個元素必是最大(小)元素。 代碼 import ...
  • ArrayBlockingQueue介紹 ArrayBlockingQueue是最典型的有界阻塞隊列,其內部是用數組存儲元素的,初始化時需要指定容量大小,利用 ReentrantLock 實現線程安全。 在生產者-消費者模型中使用時,如果生產速度和消費速度基本匹配的情況下,使用ArrayBlocki ...
  • springboot結合redis做緩存,在@Cacheable中使用如下SpEL時報錯。 @Cacheable(cacheNames = ENTERPRISE_CACHE_KEY, key = "#{T(com.emax.common.RestApiSignUtil).foo(#root.args ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...