SpringBoot 整合MyBatis-Plus3.1詳細教程

Sans_發表於2019-06-09

一.說明

Mybatis-Plus官網:mp.baomidou.com/

Mybatis-Plus是一個Mybatis框架的增強外掛,根據官方描述,MP只做增強不做改變,引入它不會對現有工程產生影響,如絲般順滑.並且只需簡單配置,即可快速進行 CRUD 操作,從而節省大量時間.程式碼生成,分頁,效能分析等功能一應俱全,最新已經更新到了3.1.1版本了,3.X系列支援lambda語法,讓我在寫條件構造的時候少了很多的"魔法值",從程式碼結構上更簡潔了.

二.專案環境

MyBatis-Plus版本: 3.1.0

SpringBoot版本:2.1.5

JDK版本:1.8

Maven依賴如下:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </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>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- mybatisPlus 核心庫 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.1.0</version>
        </dependency>
        <!-- 引入阿里資料庫連線池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.6</version>
        </dependency>
</dependencies>
複製程式碼

配置如下:

# 配置埠
server:
  port: 8081
spring:
  # 配置資料來源
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mp_student?useUnicode=true&characterEncoding=utf-8
    username: root
    password: root
    type: com.alibaba.druid.pool.DruidDataSource
# mybatis-plus相關配置
mybatis-plus:
  # xml掃描,多個目錄用逗號或者分號分隔(告訴 Mapper 所對應的 XML 檔案位置)
  mapper-locations: classpath:mapper/*.xml
  # 以下配置均有預設值,可以不設定
  global-config:
    db-config:
      #主鍵型別 AUTO:"資料庫ID自增" INPUT:"使用者輸入ID",ID_WORKER:"全域性唯一ID (數字型別唯一ID)", UUID:"全域性唯一ID UUID";
      id-type: auto
      #欄位策略 IGNORED:"忽略判斷"  NOT_NULL:"非 NULL 判斷")  NOT_EMPTY:"非空判斷"
      field-strategy: NOT_EMPTY
      #資料庫型別
      db-type: MYSQL
  configuration:
    # 是否開啟自動駝峰命名規則對映:從資料庫列名到Java屬性駝峰命名的類似對映
    map-underscore-to-camel-case: true
    # 返回map時true:當查詢資料為空時欄位返回為null,false:不加這個查詢資料為空時,欄位將被隱藏
    call-setters-on-nulls: true
    # 這個配置會將執行的sql列印出來,在開發或測試的時候可以用
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
複製程式碼

表結構:

CREATE TABLE `user_info` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `name` varchar(32) DEFAULT NULL COMMENT '姓名',
  `age` int(11) DEFAULT NULL COMMENT '年齡',
  `skill` varchar(32) DEFAULT NULL COMMENT '技能',
  `evaluate` varchar(64) DEFAULT NULL COMMENT '評價',
  `fraction` bigint(11) DEFAULT NULL COMMENT '分數',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 COMMENT='學生資訊表';
複製程式碼

表資料:

INSERT INTO `user_info` VALUES (1, '小明', 20, '畫畫', '該學生在畫畫方面有一定天賦', 89);
INSERT INTO `user_info` VALUES (2, '小蘭', 19, '遊戲', '近期該學生由於遊戲的原因導致分數降低了', 64);
INSERT INTO `user_info` VALUES (3, '張張', 18, '英語', '近期該學生參加英語比賽獲得二等獎', 90);
INSERT INTO `user_info` VALUES (4, '大黃', 20, '體育', '該學生近期由於參加籃球比賽,導致腳傷', 76);
INSERT INTO `user_info` VALUES (5, '大白', 17, '繪畫', '該學生參加美術大賽獲得三等獎', 77);
INSERT INTO `user_info` VALUES (7, '小龍', 18, 'JAVA', '該學生是一個在改BUG的碼農', 59);
INSERT INTO `user_info` VALUES (9, 'Sans', 18, '睡覺', 'Sans是一個愛睡覺,並且身材較矮骨骼巨大的骷髏小胖子', 60);
INSERT INTO `user_info` VALUES (10, 'papyrus', 18, 'JAVA', 'Papyrus是一個講話大聲、個性張揚的骷髏,給人自信、有魅力的骷髏小瘦子', 58);
INSERT INTO `user_info` VALUES (11, '刪除資料1', 3, '畫肖像', NULL, 61);
INSERT INTO `user_info` VALUES (12, '刪除資料2', 3, NULL, NULL, 61);
INSERT INTO `user_info` VALUES (13, '刪除資料3', 3, NULL, NULL, 61);
INSERT INTO `user_info` VALUES (14, '刪除資料4', 5, '刪除', NULL, 10);
INSERT INTO `user_info` VALUES (15, '刪除資料5', 6, '刪除', NULL, 10);
複製程式碼

二.編寫基礎類

在啟動類上新增掃描DAO的註解

@SpringBootApplication
@MapperScan(basePackages = {"com.mp.demo.dao"}) //掃描DAO
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
複製程式碼

編寫Config配置類

/**
 * @Description MybatisPlus配置類
 * @Author Sans
 * @CreateTime 2019/5/26 17:20
 */
@Configuration
public class MybatisPlusConfig {
    /**
     * mybatis-plus SQL執行效率外掛【生產環境可以關閉】
     */
    @Bean
    public PerformanceInterceptor performanceInterceptor() {
        return new PerformanceInterceptor();
    }
    /**
     * 分頁外掛
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
}
複製程式碼

編寫Entity類

/**
 * @Description 學生資訊實體類
 * @Author Sans
 * @CreateTime 2019/5/26 21:41
 */
@Data
@TableName("user_info")//@TableName中的值對應著表名
public class UserInfoEntity {

    /**
     * 主鍵
     * @TableId中可以決定主鍵的型別,不寫會採取預設值,預設值可以在yml中配置
     * AUTO: 資料庫ID自增
     * INPUT: 使用者輸入ID
     * ID_WORKER: 全域性唯一ID,Long型別的主鍵
     * ID_WORKER_STR: 字串全域性唯一ID
     * UUID: 全域性唯一ID,UUID型別的主鍵
     * NONE: 該型別為未設定主鍵型別
     */
    @TableId(type = IdType.AUTO)
    private Long id;
    /**
     * 姓名
     */
    private String name;
    /**
     * 年齡
     */
    private Integer age;
    /**
     * 技能
     */
    private String skill;
    /**
     * 評價
     */
    private String evaluate;
    /**
     * 分數
     */
    private Long fraction;
}
複製程式碼

編寫Dao類

/**
 * @Description 使用者資訊DAO
 * @Author Sans
 * @CreateTime 2019/6/8 16:24
 */
public interface UserInfoDao extends BaseMapper<UserInfoEntity> {
}
複製程式碼

編寫Service類

/**
 * @Description 使用者業務介面
 * @Author Sans
 * @CreateTime 2019/6/8 16:26
 */
public interface UserInfoService extends IService<UserInfoEntity> {
}
複製程式碼

編寫ServiceImpl類

/**
 * @Description 使用者業務實現
 * @Author Sans
 * @CreateTime 2019/6/8 16:26
 */
@Service
@Transactional
public class UserInfoSerivceImpl extends ServiceImpl<UserInfoDao, UserInfoEntity> implements UserInfoService {
}
複製程式碼

三.MyBatis-Plus基礎演示

這裡我們看到,service中我們沒有寫任何方法,MyBatis-Plus官方封裝了許多基本CRUD的方法,可以直接使用大量節約時間,MP共通方法詳見IService,ServiceImpl,BaseMapper原始碼,寫入操作在ServiceImpl中已有事務繫結,這裡我們舉一些常用的方法演示.

/**
 * @Description UserInfoController
 * @Author Sans
 * @CreateTime 2019/6/8 16:27
 */
@RestController
@RequestMapping("/userInfo")
public class UserInfoController {

    @Autowired
    private UserInfoService userInfoService;

    /**
     * 根據ID獲取使用者資訊
     * @Author Sans
     * @CreateTime 2019/6/8 16:34
     * @Param  userId  使用者ID
     * @Return UserInfoEntity 使用者實體
     */
    @RequestMapping("/getInfo")
    public UserInfoEntity getInfo(String userId){
        UserInfoEntity userInfoEntity = userInfoService.getById(userId);
        return userInfoEntity;
    }
    /**
     * 查詢全部資訊
     * @Author Sans
     * @CreateTime 2019/6/8 16:35
     * @Param  userId  使用者ID
     * @Return List<UserInfoEntity> 使用者實體集合
     */
    @RequestMapping("/getList")
    public List<UserInfoEntity> getList(){
        List<UserInfoEntity> userInfoEntityList = userInfoService.list();
        return userInfoEntityList;
    }
    /**
     * 分頁查詢全部資料
     * @Author Sans
     * @CreateTime 2019/6/8 16:37
     * @Return IPage<UserInfoEntity> 分頁資料
     */
    @RequestMapping("/getInfoListPage")
    public IPage<UserInfoEntity> getInfoListPage(){
        //需要在Config配置類中配置分頁外掛
        IPage<UserInfoEntity> page = new Page<>();
        page.setCurrent(5); //當前頁
        page.setSize(1);    //每頁條數
        page = userInfoService.page(page);
        return page;
    }
    /**
     * 根據指定欄位查詢使用者資訊集合
     * @Author Sans
     * @CreateTime 2019/6/8 16:39
     * @Return Collection<UserInfoEntity> 使用者實體集合
     */
    @RequestMapping("/getListMap")
    public Collection<UserInfoEntity> getListMap(){
        Map<String,Object> map = new HashMap<>();
        //kay是欄位名 value是欄位值
        map.put("age",20);
        Collection<UserInfoEntity> userInfoEntityList = userInfoService.listByMap(map);
        return userInfoEntityList;
    }
    /**
     * 新增使用者資訊
     * @Author Sans
     * @CreateTime 2019/6/8 16:40
     */
    @RequestMapping("/saveInfo")
    public void saveInfo(){
        UserInfoEntity userInfoEntity = new UserInfoEntity();
        userInfoEntity.setName("小龍");
        userInfoEntity.setSkill("JAVA");
        userInfoEntity.setAge(18);
        userInfoEntity.setFraction(59L);
        userInfoEntity.setEvaluate("該學生是一個在改BUG的碼農");
        userInfoService.save(userInfoEntity);
    }
    /**
     * 批量新增使用者資訊
     * @Author Sans
     * @CreateTime 2019/6/8 16:42
     */
    @RequestMapping("/saveInfoList")
    public void saveInfoList(){
        //建立物件
        UserInfoEntity sans = new UserInfoEntity();
        sans.setName("Sans");
        sans.setSkill("睡覺");
        sans.setAge(18);
        sans.setFraction(60L);
        sans.setEvaluate("Sans是一個愛睡覺,並且身材較矮骨骼巨大的骷髏小胖子");
        UserInfoEntity papyrus = new UserInfoEntity();
        papyrus.setName("papyrus");
        papyrus.setSkill("JAVA");
        papyrus.setAge(18);
        papyrus.setFraction(58L);
        papyrus.setEvaluate("Papyrus是一個講話大聲、個性張揚的骷髏,給人自信、有魅力的骷髏小瘦子");
        //批量儲存
        List<UserInfoEntity> list =new ArrayList<>();
        list.add(sans);
        list.add(papyrus);
        userInfoService.saveBatch(list);
    }
    /**
     * 更新使用者資訊
     * @Author Sans
     * @CreateTime 2019/6/8 16:47
     */
    @RequestMapping("/updateInfo")
    public void updateInfo(){
        //根據實體中的ID去更新,其他欄位如果值為null則不會更新該欄位,參考yml配置檔案
        UserInfoEntity userInfoEntity = new UserInfoEntity();
        userInfoEntity.setId(1L);
        userInfoEntity.setAge(19);
        userInfoService.updateById(userInfoEntity);
    }
    /**
     * 新增或者更新使用者資訊
     * @Author Sans
     * @CreateTime 2019/6/8 16:50
     */
    @RequestMapping("/saveOrUpdateInfo")
    public void saveOrUpdate(){
        //傳入的實體類userInfoEntity中ID為null就會新增(ID自增)
        //實體類ID值存在,如果資料庫存在ID就會更新,如果不存在就會新增
        UserInfoEntity userInfoEntity = new UserInfoEntity();
        userInfoEntity.setId(1L);
        userInfoEntity.setAge(20);
        userInfoService.saveOrUpdate(userInfoEntity);
    }
    /**
     * 根據ID刪除使用者資訊
     * @Author Sans
     * @CreateTime 2019/6/8 16:52
     */
    @RequestMapping("/deleteInfo")
    public void deleteInfo(String userId){
        userInfoService.removeById(userId);
    }
    /**
     * 根據ID批量刪除使用者資訊
     * @Author Sans
     * @CreateTime 2019/6/8 16:55
     */
    @RequestMapping("/deleteInfoList")
    public void deleteInfoList(){
        List<String> userIdlist = new ArrayList<>();
        userIdlist.add("12");
        userIdlist.add("13");
        userInfoService.removeByIds(userIdlist);
    }
    /**
     * 根據指定欄位刪除使用者資訊
     * @Author Sans
     * @CreateTime 2019/6/8 16:57
     */
    @RequestMapping("/deleteInfoMap")
    public void deleteInfoMap(){
        //kay是欄位名 value是欄位值
        Map<String,Object> map = new HashMap<>();
        map.put("skill","刪除");
        map.put("fraction",10L);
        userInfoService.removeByMap(map);
    }
}
複製程式碼

四.MyBatis-Plus的QueryWrapper條件構造器

當查詢條件複雜的時候,我們可以使用MP的條件構造器,請參考下面的QueryWrapper條件引數說明

查詢方式 方法說明
setSqlSelect 設定 SELECT 查詢欄位
where WHERE 語句,拼接 + WHERE 條件
and AND 語句,拼接 + AND 欄位=值
or OR 語句,拼接 + OR 欄位=值
eq 等於=
allEq 基於 map 內容等於=
ne 不等於<>
gt 大於>
ge 大於等於>=
lt 小於<
le 小於等於<=
like 模糊查詢 LIKE
notLike 模糊查詢 NOT LIKE
in IN 查詢
notIn NOT IN 查詢
isNull NULL 值查詢
isNotNull IS NOT NULL
groupBy 分組 GROUP BY
having HAVING 關鍵詞
orderBy 排序 ORDER BY
orderByAsc ASC 排序 ORDER BY
orderByDesc DESC 排序 ORDER BY
exists EXISTS 條件語句
notExists NOT EXISTS 條件語句
between BETWEEN 條件語句
notBetween NOT BETWEEN 條件語句
addFilter 自由拼接 SQL
last 拼接在最後,例如:last("LIMIT 1")

下面我們來舉一些常見的示例

/**
 * @Description UserInfoPlusController
 * @Author Sans
 * @CreateTime 2019/6/9 14:52
 */
@RestController
@RequestMapping("/userInfoPlus")
public class UserInfoPlusController {

    @Autowired
    private UserInfoService userInfoService;

    /**
     * MP擴充套件演示
     * @Author Sans
     * @CreateTime 2019/6/8 16:37
     * @Return Map<String,Object> 返回資料
     */
    @RequestMapping("/getInfoListPlus")
    public Map<String,Object> getInfoListPage(){
        //初始化返回類
        Map<String,Object> result = new HashMap<>();
        //查詢年齡等於18歲的學生
        //等價SQL: SELECT id,name,age,skill,evaluate,fraction FROM user_info WHERE age = 18
        QueryWrapper<UserInfoEntity> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.lambda().eq(UserInfoEntity::getAge,18);
        List<UserInfoEntity> userInfoEntityList1 = userInfoService.list(queryWrapper1);
        result.put("studentAge18",userInfoEntityList1);
        //查詢年齡大於5歲的學生且小於等於18歲的學生
        //等價SQL: SELECT id,name,age,skill,evaluate,fraction FROM user_info WHERE age > 5 AND age <= 18
        QueryWrapper<UserInfoEntity> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.lambda().gt(UserInfoEntity::getAge,5);
        queryWrapper2.lambda().le(UserInfoEntity::getAge,18);
        List<UserInfoEntity> userInfoEntityList2 = userInfoService.list(queryWrapper2);
        result.put("studentAge5",userInfoEntityList2);
        //模糊查詢技能欄位帶有"畫"的資料,並按照年齡降序
        //等價SQL: SELECT id,name,age,skill,evaluate,fraction FROM user_info WHERE skill LIKE '%畫%' ORDER BY age DESC
        QueryWrapper<UserInfoEntity> queryWrapper3 = new QueryWrapper<>();
        queryWrapper3.lambda().like(UserInfoEntity::getSkill,"畫");
        queryWrapper3.lambda().orderByDesc(UserInfoEntity::getAge);
        List<UserInfoEntity> userInfoEntityList3 = userInfoService.list(queryWrapper3);
        result.put("studentAgeSkill",userInfoEntityList3);
        //模糊查詢名字帶有"小"或者年齡大於18的學生
        //等價SQL: SELECT id,name,age,skill,evaluate,fraction FROM user_info WHERE name LIKE '%小%' OR age > 18
        QueryWrapper<UserInfoEntity> queryWrapper4 = new QueryWrapper<>();
        queryWrapper4.lambda().like(UserInfoEntity::getName,"小");
        queryWrapper4.lambda().or().gt(UserInfoEntity::getAge,18);
        List<UserInfoEntity> userInfoEntityList4 = userInfoService.list(queryWrapper4);
        result.put("studentOr",userInfoEntityList4);
        //查詢評價不為null的學生,並且分頁
        //等價SQL: SELECT id,name,age,skill,evaluate,fraction FROM user_info WHERE evaluate IS NOT NULL LIMIT 0,5
        IPage<UserInfoEntity> page = new Page<>();
        page.setCurrent(1);
        page.setSize(5);
        QueryWrapper<UserInfoEntity> queryWrapper5 = new QueryWrapper<>();
        queryWrapper5.lambda().isNotNull(UserInfoEntity::getEvaluate);
        page = userInfoService.page(page,queryWrapper5);
        result.put("studentPage",page);
        return result;
    }
}
複製程式碼

五.自定義SQL

引入Mybatis-Plus不會對專案現有的 Mybatis 構架產生任何影響,而且Mybatis-Plus支援所有 Mybatis 原生的特性,這也是我喜歡使用它的原因之一,由於某些業務複雜,我們可能要自己去寫一些比較複雜的SQL語句,我們舉一個簡單的例子來演示自定義SQL.

示例:查詢大於設定分數的學生(分數為動態輸入,且有分頁)

編寫Mapper.xml檔案

<mapper namespace="com.mp.demo.dao.UserInfoDao">
    <!-- Sans 2019/6/9 14:35 -->
    <select id="selectUserInfoByGtFraction" resultType="com.mp.demo.entity.UserInfoEntity" parameterType="long">
	SELECT * FROM user_info WHERE fraction > #{fraction}
    </select>
</mapper>
複製程式碼

在DAO中加入方法

    /**
     * 查詢大於該分數的學生
     * @Author Sans
     * @CreateTime 2019/6/9 14:28
     * @Param  page  分頁引數
     * @Param  fraction  分數
     * @Return IPage<UserInfoEntity> 分頁資料
     */
    IPage<UserInfoEntity> selectUserInfoByGtFraction(IPage<UserInfoEntity> page, Long fraction);
複製程式碼

在service加入方法

    /**
     * 查詢大於該分數的學生
     * @Author Sans
     * @CreateTime 2019/6/9 14:27
     * @Param  page  分頁引數
     * @Param  fraction  分數
     * @Return IPage<UserInfoEntity> 分頁資料
     */
    IPage<UserInfoEntity> selectUserInfoByGtFraction(IPage<UserInfoEntity> page,Long fraction);
複製程式碼

在serviceImpl加入方法

    /**
     * 查詢大於該分數的學生
     * @Author Sans
     * @CreateTime 2019/6/9 14:27
     * @Param  page  分頁引數
     * @Param  fraction  分數
     * @Return IPage<UserInfoEntity> 分頁資料
     */
    @Override
    public IPage<UserInfoEntity> selectUserInfoByGtFraction(IPage<UserInfoEntity> page, Long fraction) {
        return this.baseMapper.selectUserInfoByGtFraction(page,fraction);
    }
複製程式碼

在Controller中測試

    /**
     * MP自定義SQL
     * @Author Sans
     * @CreateTime 2019/6/9 14:37
     * @Return IPage<UserInfoEntity> 分頁資料
     */
    @RequestMapping("/getInfoListSQL")
    public IPage<UserInfoEntity> getInfoListSQL(){
        //查詢大於60分以上的學生,並且分頁
        IPage<UserInfoEntity> page = new Page<>();
        page.setCurrent(1);
        page.setSize(5);
        page = userInfoService.selectUserInfoByGtFraction(page,60L);
        return page;
    }
複製程式碼

六.專案原始碼

專案原始碼: gitee.com/liselotte/s…

個人確實很喜歡用MyBatis-Plus,不僅節約時間,程式碼也簡潔乾淨,它給了我那時候從SSM到SpringBoot過度的那種感覺

嗯,這玩意真香~

謝謝大家閱讀,如果喜歡,請收藏點贊,文章不足之處,也請給出寶貴意見.

相關文章