簡介
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 的其他功能後續會繼續嘗試更新。