MyBatis-Plus | 最優雅最簡潔地完成資料庫操作
引言
兩點:
一,使用MyBatis-Plus最新版(3.0.1)完成相關操作
二,好久沒寫MyBatis操作資料庫的博文了,有沒有想我啊,哈哈,認真看,認真聽,認真學。
測試效果:
下面聽我細細道來,MyBatis-Plus的優雅、簡潔與強大。
程式碼生成器
程式碼生成器,又被叫做逆向工程,MyBatis官方為了推廣,自己也寫了一個,我之前也使用這個,功能也是非常強大,強大以為支援自定義配置,那麼問題來了,我該怎麼配置才合理呢,所以,有人把所有的配置項都弄成中文的,還有人開發了生成外掛,這些在我以往的博文中都看看到。MyBatis-Plus的程式碼生成器到底怎麼樣,這我就不評判了,我就這樣說,用用看吧。
在MyBatis-Plus的官網文件中,有將程式碼生成器的問題,有配置詳解,也有專案示例程式碼,複製來就可用。
我這次是用MP 3.0.1,也就是最新版,官方還沒有更新呢,所以,我去找了很久的原始碼,才將這個完成,勉強適合自己的了。這個在 CodeGenerator
Module中,可以下下下來,匯入到IDE中,看一下,修改配置就能執行。有問題,也可以與我討論。
功能列表:
[✔] 自動生成model類
[✔] 自動生成dao介面
[✔] 自動生成xml檔案
[✔] 自動生成service介面
[✔] 自動生成service實現類
[✔] model支援Builder模式
[✔] 支援swagger2
[✔] 支援生成資料庫欄位常量
[✔] 支援生成Kotlin程式碼
[] ……
專案初始化
第一步:pom.xml引入MyBatis-Plus依賴,注意,不需要再引入MyBatis的包,因為我這裡使用Spring Boot搭建的工程,所有因為方式見下:
<dependencies>
...
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId >
<version>3.0.1</version>
</dependency>
...
</dependencies>
第二步:將生成的程式碼,拷貝到相應的包下
第三步:在配置檔案中進行相應的配置
具體配置可參考官網,這裡需要注意這樣幾個地方:
mybatis-plus:
# xml
mapper-locations: classpath:mapper/*Mapper.xml
# 實體掃描,多個package用逗號或者分號分隔
type-aliases-package: com.fengwenyi.mp3demo.model
configuration:
# 這個配置會將執行的sql打印出來,在開發或測試的時候可以用
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
第四步:在啟動類上新增下面的註解
@EnableTransactionManagement
@MapperScan("com.fengwenyi.mp3demo.dao")
增刪改
Service
我們一起去看原始碼 com.baomidou.mybatisplus.extension.service.IService<T>
增加:
/**
* <p>
* 插入一條記錄(選擇欄位,策略插入)
* </p>
*
* @param entity 實體物件
*/
boolean save(T entity);
修改:
/**
* <p>
* 根據 ID 選擇修改
* </p>
*
* @param entity 實體物件
*/
boolean updateById(T entity);
/**
* <p>
* 根據 whereEntity 條件,更新記錄
* </p>
*
* @param entity 實體物件
* @param updateWrapper 實體物件封裝操作類
* {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
*/
boolean update(T entity, Wrapper<T> updateWrapper);
刪除:
/**
* <p>
* 根據 ID 刪除
* </p>
*
* @param id 主鍵ID
*/
boolean removeById(Serializable id);
/**
* <p>
* 根據 entity 條件,刪除記錄
* </p>
*
* @param queryWrapper 實體包裝類
* {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
boolean remove(Wrapper<T> queryWrapper);
Mapper
com.baomidou.mybatisplus.core.mapper.BaseMapper<T>
增加:
/**
* <p>
* 插入一條記錄
* </p>
*
* @param entity 實體物件
*/
int insert(T entity);
修改:
/**
* <p>
* 根據 whereEntity 條件,更新記錄
* </p>
*
* @param entity 實體物件 (set 條件值,不能為 null)
* @param updateWrapper 實體物件封裝操作類(可以為 null,裡面的 entity 用於生成 where 語句)
*/
int update(@Param(Constants.ENTITY) T entity,
@Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
/**
* <p>
* 根據 ID 修改
* </p>
*
* @param entity 實體物件
*/
int updateById(@Param(Constants.ENTITY) T entity);
刪除:
/**
* <p>
* 根據 entity 條件,刪除記錄
* </p>
*
* @param queryWrapper 實體物件封裝操作類(可以為 null)
*/
int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* <p>
* 根據 ID 刪除
* </p>
*
* @param id 主鍵ID
*/
int deleteById(Serializable id);
以上相當於是常用API了,我們去看看,他是怎麼實現的。毫無疑問,Mapper是底層,Service呼叫Mapper去執行sql,完成相關操作,所以,你完全可以直接呼叫Mapper完成相關操作,就跟使用MyBatis一樣。下面我們去看看,他幫我們寫的Service是什麼樣子,這裡只看一個修改操作吧。
介面:
/**
* <p>
* 根據 whereEntity 條件,更新記錄
* </p>
*
* @param entity 實體物件
* @param updateWrapper 實體物件封裝操作類
* {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
*/
boolean update(T entity, Wrapper<T> updateWrapper);
實現:
@Override
public boolean update(T entity, Wrapper<T> updateWrapper) {
return ServiceImpl.retBool(baseMapper.update(entity, updateWrapper));
}
/**
* <p>
* 判斷資料庫操作是否成功
* </p>
* <p>
* 注意!! 該方法為 Integer 判斷,不可傳入 int 基本型別
* </p>
*
* @param result 資料庫操作返回影響條數
* @return boolean
*/
protected static boolean retBool(Integer result) {
return SqlHelper.retBool(result);
}
/**
* <p>
* 判斷資料庫操作是否成功
* </p>
*
* @param result 資料庫操作返回影響條數
* @return boolean
*/
public static boolean retBool(Integer result) {
return null != result && result >= 1;
}
哈哈,是不是我們自己也會這樣寫啊!
查詢
接下來,我們一起討論下查詢吧。
MP 3.x,查詢介面發生了很大的變化,反正我是不喜歡的,你就弄一個什麼開頭啊,到時候,我一點就知道有哪些方法了,他這裡有 list*
, get*
,反正就是一個字——沒必要。
先看下介面說明:
/**
* <p>
* 查詢列表
* </p>
*
* @param queryWrapper 實體物件封裝操作類
* {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
List<T> list(Wrapper<T> queryWrapper);
/**
* <p>
* 根據 ID 查詢
* </p>
*
* @param id 主鍵ID
*/
T getById(Serializable id);
/**
* <p>
* 根據 Wrapper,查詢一條記錄
* </p>
*
* @param queryWrapper 實體物件封裝操作類
* {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
T getOne(Wrapper<T> queryWrapper);
嗯,差不多了吧,這樣需要注意這樣一個方法:
/**
* <p>
* 從list中取第一條資料返回對應List中泛型的單個結果
* </p>
*
* @param list
* @param <E>
* @return
*/
public static <E> E getObject(List<E> list) {
if (CollectionUtils.isNotEmpty(list)) {
int size = list.size();
if (size > 1) {
SqlHelper.logger.warn(
String.format("Warn: execute Method There are %s results.", size));
}
return list.get(0);
}
return null;
}
下面說下分頁的問題
根據官網的說法,需要藉助外掛,這我們是可以理解。
在Spring Boot啟動類裡面新增:
/**
* 分頁外掛
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
這樣就可以使用他提供的分頁介面了:
/**
* <p>
* 翻頁查詢
* </p>
*
* @param page 翻頁物件
* @param queryWrapper 實體物件封裝操作類
* {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
*/
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
我們去看一下:
@Override
public IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper) {
queryWrapper = (Wrapper<T>) SqlHelper.fillWrapper(page, queryWrapper);
return baseMapper.selectPage(page, queryWrapper);
}
/**
* <p>
* 填充Wrapper
* </p>
*
* @param page 分頁物件
* @param wrapper SQL包裝物件
*/
@SuppressWarnings("unchecked")
public static Wrapper<?> fillWrapper(IPage<?> page, Wrapper<?> wrapper) {
if (null == page) {
return wrapper;
}
if (ArrayUtils.isEmpty(page.ascs())
&& ArrayUtils.isEmpty(page.descs())
&& ObjectUtils.isEmpty(page.condition())) {
return wrapper;
}
QueryWrapper qw;
if (null == wrapper) {
qw = new QueryWrapper<>();
} else {
qw = (QueryWrapper) wrapper;
}
// 排序
if (ArrayUtils.isNotEmpty(page.ascs())) {
qw.orderByAsc(page.ascs());
}
if (ArrayUtils.isNotEmpty(page.descs())) {
qw.orderByDesc(page.descs());
}
// MAP 引數查詢
if (ObjectUtils.isNotEmpty(page.condition())) {
qw.allEq(page.condition());
}
return qw;
}
/**
* <p>
* 根據 entity 條件,查詢全部記錄(並翻頁)
* </p>
*
* @param page 分頁查詢條件(可以為 RowBounds.DEFAULT)
* @param queryWrapper 實體物件封裝操作類(可以為 null)
*/
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
分頁的程式碼大抵就是這樣,我之前也自己寫過,思路還是相當來說比較簡單,關鍵是看你的查詢新增如何封裝,分頁類如何構造。
這裡有一點說明:
分頁從 1
開始 !!!
列舉類
1、實現 介面
/**
* <p>
* 自定義列舉介面
* </p>
*
* @author hubin
* @since 2017-10-11
*/
public interface IEnum<T extends Serializable> {
/**
* 列舉資料庫儲存值
*/
T getValue();
}
2、實現注意
@Override
public Integer getValue() {
return this.value;
}
@JsonValue
public String getDesc() {
return desc;
}
這是Jackson的寫法,我沒用FastJson,所以用的夥伴,去官網看一下:FastJson看官網。
3:被忘了在配置檔案中新增掃描:
mybatis-plus:
# 掃描列舉類 # 支援統配符 * 或者 ; 分割
type-enums-package: com.fengwenyi.mp3demo.enums
差不多了吧,好像
邏輯刪除
1、程式碼生成器中配置:
new StrategyConfig().setLogicDeleteFieldName("is_delete") // 邏輯刪除屬性名稱
或者,你可以手寫,參考:
@ApiModelProperty(value = "是否邏輯刪除(true:刪除;false:正常(預設))")
@TableLogic
private Boolean isDelete;
2、自定義資料庫的值:
mybatis-plus:
global-config:
db-config:
#邏輯刪除配置
logic-delete-value: 1
logic-not-delete-value: 0
MyBatis-Plus-Example
MyBatis-Plus的程式碼都會上傳到github上