SpringBoot 整合Mybatis-Plus

簡介

MyBatis-Plus(簡稱 MP)是一個 MyBatis 的增強工具,在 MyBatis 的基礎上只做增強不做改變,爲簡化開發、提高效率而生。

特性

  • 無侵入:只做增強不做改變,引入它不會對現有工程產生影響,如絲般順滑
  • 損耗小:啓動即會自動注入基本 CURD,性能基本無損耗,直接面向對象操作
  • 強大的 CRUD 操作:內置通用 Mapper、通用 Service,僅僅通過少量配置即可實現單表大部分 CRUD 操作,更有強大的條件構造器,滿足各類使用需求
  • 支持 Lambda 形式調用:通過 Lambda 表達式,方便的編寫各類查詢條件,無需再擔心字段寫錯
  • 支持主鍵自動生成:支持多達 4 種主鍵策略(內含分佈式唯一 ID 生成器 - Sequence),可自由配置,完美解決主鍵問題
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式調用,實體類只需繼承 Model 類即可進行強大的 CRUD 操作
  • 支持自定義全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 內置代碼生成器:採用代碼或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 層代碼,支持模板引擎,更有超多自定義配置等您來使用
  • 內置分頁插件:基於 MyBatis 物理分頁,開發者無需關心具體操作,配置好插件之後,寫分頁等同於普通 List 查詢
  • 分頁插件支持多種數據庫:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多種數據庫
  • 內置性能分析插件:可輸出 Sql 語句以及其執行時間,建議開發測試時啓用該功能,能快速揪出慢查詢
  • 內置全局攔截插件:提供全表 delete 、 update 操作智能分析阻斷,也可自定義攔截規則,預防誤操作

快速上手

首先需要一個springboot 項目

在這裏插入圖片描述
引入MyBatis-Plus 的maven依賴(舊項目注意刪除mybatis 相關的依賴):

<dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

在application.yml 裏面配置你的mysql 連接信息和Mybatis-Plus 配置


spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/central_certification?useUnicode=true&characterEncoding=utf8
    username: root
    password: 123456

mybatis-plus:
  //自定義sql 路徑
  mapper-locations: classpath*:/mapper/**/*.xml

我們在對應數據庫新建一個user 表:

CREATE TABLE `central_certification`.`user`  (
  `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '用戶表自增id',
  `user_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '用戶名稱',
  `mail` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '用戶郵箱',
  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '用戶密碼',
  `deleted` tinyint(1) NULL DEFAULT 0 COMMENT '是否刪除(0 正常 1 刪除)',
  `create_time` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT '創建時間',
  `update_time` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '更新時間',
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `idx_mail_password`(`mail`) USING BTREE COMMENT '郵箱索引'
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic;

// 插入數據
INSERT INTO `user` VALUES (5, 'wt', '[email protected]', '123456', 0, '2019-12-27 16:37:46', '2019-12-30 12:43:56');
INSERT INTO `user` VALUES (6, '唐江席', '[email protected]', '123456', 0, '2019-12-27 17:22:23', '2019-12-27 17:22:23');


在bean 目錄下新建User 類:


import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.Data;

import java.io.Serializable;
import java.time.LocalDateTime;

@Data
@Builder
@TableName("user")
public class User extends Model<User> {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String userName;
    private String password;
    private String mail;
    private Integer deleted;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
}

@TableName 用於指定類對應的數據庫
@TableId 用於指定自增id 及其id 生產規則:

// 可指定的規則
   AUTO(0),
   NONE(1),
   INPUT(2),
   ASSIGN_ID(3),
   ASSIGN_UUID(4),
   /** @deprecated */
   @Deprecated
   ID_WORKER(3),
   /** @deprecated */
   @Deprecated
   ID_WORKER_STR(3),
   /** @deprecated */
   @Deprecated
   UUID(4);

Model<T> 類是Mybtais-Plus 的特性支持之一

支持 ActiveRecord 模式:支持 ActiveRecord 形式調用,實體類只需繼承 Model 類即可進行強大的 CRUD 操作

什麼意思呢,就是說我們可以直接使用類的對象來實現CRUD 操作,可以看看Model<T> 類中的方法:
在這裏插入圖片描述
這些方法不但方便還做了比較完備的檢查,比如insertOrUpdate

// 根據id 來判斷是否存在,存在更新,否則新增
public boolean insertOrUpdate() {
        return !StringUtils.checkValNull(this.pkVal()) && !Objects.isNull(this.selectById(this.pkVal())) ? this.updateById() : this.insert();
    }

我們來測試一下:

@org.junit.Test
    public void test2(){
        User user = User.builder()
                        .userName("test")
                        .mail("testMail")
                        .password("test")
                        .build();
        user.insert();
        System.out.println(userMapper.queryByMail("testMail"));
    }
    
User(id=7, userName=test, password=test, mail=testMail, deleted=0, createTime=2020-02-01T20:11:37, updateTime=2020-02-01T20:11:37)

除了繼承的方式,我們還可以通過接口來實現,在mapper 裏面新建UserMapper:

package com.example.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.bean.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface UserMapper  extends BaseMapper<User> {
}

@Mapper 可以聲明一個mapper ,除此之外可以在啓動類指定掃描:

@SpringBootApplication
@MapperScan("com.example.demo.mapper")
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

BaseMapper 也定義了一些常用的方法可以使用
在這裏插入圖片描述

@SpringBootTest
@RunWith(SpringRunner.class)
public class Test {
    @Autowired
    private UserMapper userMapper;

    @org.junit.Test
    public void test(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("deleted", 0);
        List<User> users = userMapper.selectList(queryWrapper);
        users.forEach(v -> {
            System.out.println(v);
        });
    }
}

User(id=5, userName=wt, password=123456, [email protected], deleted=0, createTime=2019-12-27T16:37:46, updateTime=2019-12-30T12:43:56)
User(id=6, userName=唐江席, password=123456, [email protected], deleted=0, createTime=2019-12-27T17:22:23, updateTime=2019-12-27T17:22:23)
User(id=7, userName=test, password=test, mail=testMail, deleted=0, createTime=2020-02-01T20:11:37, updateTime=2020-02-01T20:11:37)

自定義sql

如果想自己寫sql ,就和mybatis 一樣

@Mapper
public interface UserMapper  extends BaseMapper<User> {
    User queryByMail(@Param("mail") String mail);
}

<?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.example.demo.mapper.UserMapper">

    <select id="queryByMail" resultType="com.example.demo.bean.User">
        select *
        from user
        where mail = #{mail}
    </select>
</mapper>

前面我們第一次測試的時候就用了這個方法,這裏就不重複展示了。

記得在application.yml 裏面配置映射

mybatis-plus:
  //自定義sql 路徑
  mapper-locations: classpath*:/mapper/**/*.xml

批量操作

前面的兩種方式我們發現這些方法多是些單體方法,當然還有批量的操作,在service 目錄新建一個UserServiceImpl 實現:

package com.example.demo.service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo.bean.User;
import com.example.demo.mapper.UserMapper;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> {

}

在這裏插入圖片描述
直接測試吧:

package com.example.demo.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.demo.bean.User;
import com.example.demo.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;
import java.util.stream.Collectors;

@RunWith(SpringRunner.class)
@SpringBootTest
class UserServiceImplTest {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserServiceImpl userService;

    @Test
    public void test() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("deleted", 0);
        List<User> userList = userMapper.selectList(queryWrapper);
        System.out.println("更新前:");
        userList.forEach(v -> {
            System.out.println(v);
        });
        // 批量更新userList
        userList = userList.stream().map(user -> {
            user.setUserName(user.getUserName() + "1");
            return user;
        }).collect(Collectors.toList());
        userService.updateBatchById(userList);
        List<User> userUpdateList = userMapper.selectList(queryWrapper);
        System.out.println("更新後:");
        userUpdateList.forEach(v -> {
            System.out.println(v);
        });
    }
}

更新前:
User(id=5, userName=wt, password=123456, [email protected], deleted=0, createTime=2019-12-27T16:37:46, updateTime=2019-12-30T12:43:56)
User(id=6, userName=唐江席, password=123456, [email protected], deleted=0, createTime=2019-12-27T17:22:23, updateTime=2019-12-27T17:22:23)
User(id=7, userName=test, password=test, mail=testMail, deleted=0, createTime=2020-02-01T20:11:37, updateTime=2020-02-01T20:11:37)
更新後:
User(id=5, userName=wt1, password=123456, [email protected], deleted=0, createTime=2019-12-27T02:37:46, updateTime=2019-12-29T22:43:56)
User(id=6, userName=唐江席1, password=123456, [email protected], deleted=0, createTime=2019-12-27T03:22:23, updateTime=2019-12-27T03:22:23)
User(id=7, userName=test1, password=test, mail=testMail, deleted=0, createTime=2020-02-01T06:11:37, updateTime=2020-02-01T06:11:37)

分頁操作

使用分頁需要先引入配置,不然分頁不會生效:

//Spring boot方式
@EnableTransactionManagement
@Configuration
@MapperScan("com.baomidou.cloud.service.*.mapper*")
public class MybatisPlusConfig {

    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        // 設置請求的頁面大於最大頁後操作, true調回到首頁,false 繼續請求  默認false
        // paginationInterceptor.setOverflow(false);
        // 設置最大單頁限制數量,默認 500 條,-1 不受限制
        // paginationInterceptor.setLimit(500);
        // 開啓 count 的 join 優化,只針對部分 left join
        paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
        return paginationInterceptor;
    }
}

XML 自定義分頁

UserMapper.java 方法內容

public interface UserMapper {//可以繼承或者不繼承BaseMapper
    /**
     * <p>
     * 查詢 : 根據state狀態查詢用戶列表,分頁顯示
     * </p>
     *
     * @param page 分頁對象,xml中可以從裏面進行取值,傳遞參數 Page 即自動分頁,必須放在第一位(你可以繼承Page實現自己的分頁對象)
     * @param state 狀態
     * @return 分頁對象
     */
    IPage<User> selectPageVo(Page<?> page, Integer state);
}

UserMapper.xml 等同於編寫一個普通 list 查詢,mybatis-plus 自動替你分頁

<select id="selectPageVo" resultType="com.baomidou.cloud.entity.UserVo">
    SELECT id,name FROM user WHERE state=#{state}
</select>

Mybatis-Plus 分頁

使用Mybatis-Plus 分頁可能會報錯提示無法代理

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.example.demo.service.UserServiceImplTest': 
Unsatisfied dependency expressed through field 'userService'; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'userServiceImpl' is expected to be of type 
'com.example.demo.service.UserServiceImpl' but was actually of type 'com.sun.proxy.$Proxy76'

需要在啓動類指定使用cglib

/**
 * proxy-target-class屬性值決定是基於接口的還是基於類的代理被創建。
 * 如果proxy-target-class 屬性值被設置爲true,那麼基於類的代理將起作用
 * (這時需要cglib庫)。如果proxy-target-class屬值被設置爲false或者這個
 * 屬性被省略,那麼標準的JDK 基於接口的代理
 *
 */
@EnableAsync(proxyTargetClass = true)
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}
@Test
    public void pageTest(){
        int pageNum = 1;
        int pageSize = 2;
        Page<User> page = new Page<>(pageNum, pageSize);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("deleted", 0);
        Page<User> userPage = userMapper.selectPage(page, queryWrapper);
        System.out.println("記錄:");
        userPage.getRecords().forEach(v -> {
            System.out.println(v);
        });
        System.out.println("當前頁碼" + userPage.getCurrent());
        System.out.println("總數" + userPage.getTotal());
    }
記錄:
User(id=5, userName=wt1, password=123456, [email protected], deleted=0, createTime=2019-12-27T02:37:46, updateTime=2019-12-29T22:43:56)
User(id=6, userName=唐江席1, password=123456, [email protected], deleted=0, createTime=2019-12-27T03:22:23, updateTime=2019-12-27T03:22:23)
當前頁碼1
總數3

可見總數爲3,只展示2 條記錄,分頁成功。
可以看一下Page 裏的參數:
在這裏插入圖片描述

總結

總的來說MyBatis-Plus 就是一個增強版的mybatis,它整合很多比較好用的功能,比如類似Example 的動態sql、generate 的自動生成各個層級的代碼、還有防攻擊等新功能,最關鍵是MyBatis-Plus 是非侵入的,引入不需要修改舊代碼,推薦一試。

Mybatis-Plus 的其他功能後續會繼續嘗試更新。

發佈了23 篇原創文章 · 獲贊 27 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章