前面已經介紹了Mybatis-plus基本用法,今天為大家分享一些Mybatis-plus高級應用
- 邏輯刪除
- 自動注入
- 枚舉類型處理
- Sql注入器
- 多租戶
表結構
CREATE TABLE `sys_role` ( `id` varchar(64) NOT NULL COMMENT '主鍵', `code` varchar(64) NOT NULL DEFAULT '' COMMENT '角色編碼', `name` varchar(64) NOT NULL DEFAULT '' COMMENT '角色名', `type` char(2) NOT NULL COMMENT '角色類型,1:管理員,2:普通', `tenant_code` varchar(64) NOT NULL DEFAULT '' COMMENT '租戶編碼', `create_user` varchar(64) NOT NULL DEFAULT '' COMMENT '創建用戶', `create_time` datetime NOT NULL COMMENT '創建時間', `update_user` varchar(64) NOT NULL DEFAULT '' COMMENT '更新用戶', `update_time` datetime NOT NULL COMMENT '更新時間', `is_del` char(1) NOT NULL DEFAULT '0' COMMENT '是否刪除,0:未刪除,1:刪除', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色';

邏輯刪除
全局配置
在配置文件中增加如下配置
mybatis-plus: global-config: ? db-config: ? ? logic-delete-field: isDel#全局邏輯刪除字段值 3.3.0開始支持,詳情看下面。 ? ? logic-delete-value: 1 # 邏輯已刪除值(默認為 1) ? ? logic-not-delete-value: 0 # 邏輯未刪除值(默認為 0)
局部配置
在實體類刪除字段上增加@TableLogic注解
/** 是否刪除,0:未刪除,1:刪除 */@TableLogicprivate String isDel;
全局配置和局部配置實現的結果是一樣的,下面針對局部配置做一下測試
@Autowiredprivate RoleMapper roleMapper;@Testpublic void logicDel() { ? ?roleMapper.deleteById("1");}

從結果可以看出角色id為1數據的is_del被設置為1
使用Mybatis-plus自帶方法刪除、更新和查找都會where條件后面加上刪除字段
以查詢為例看一下效果
@Test void loginDel2() { ? ?roleMapper.selectList(null);}

從打印的sql中可以看出,在where后面添加了is_del='0'限定,所以要查詢所有數據可以采用自定義sql實現
自動填充
在項目開發中,表中經常會定義一些公共的字段,例如:修改人,創建人。這時候我們可以采用 MyBatis-Plus 中
的字段自動填充功能去實現。
- 在實體類屬性上增加@TableField(fill = FieldFill.INSERT_UPDATE)注解,如下所示
@Data@TableName("sys_role")public class Role { ? ?/** 創建人 */ ? ?@TableField(fill = FieldFill.INSERT) ? ?private String createUser; ? ?/** 創建時間 */ ? ?@TableField(fill = FieldFill.INSERT) ? ?private Date createTime; ? ?/** 更新人 */ ? ?@TableField(fill = FieldFill.INSERT_UPDATE) ? ?private String updateUser; ? ?/** 更新時間 */ ? ?@TableField(fill = FieldFill.INSERT_UPDATE) ? ?private Date updateTime; ? ?/** 是否刪除,0:未刪除,1:刪除 */ ? ?@TableLogic ? ?private String isDel;}
TableField默認有四個
- DEFAULT:默認不處理
- INSERT:插入時填充字段
- UPDATE:更新時填充字段
- INSERT_UPDATE:插入和更新時填充字段
- 定義處理器
@Componentpublic class MyMetaObjectHandler implements MetaObjectHandler {? ? public static String CREATEUSER_NAMEINBEAN = "createUser"; ? ?public static String CREATETIME_NAMEINBEAN = "createTime"; ? ?public static String UPDATEUSER_NAMEINBEAN = "updateUser"; ? ?public static String UPDATETIME_NAMEINBEAN = "updateTime"; ? ?@Override ? ?public void insertFill(MetaObject metaObject) { ? ? ? ?boolean createUser = metaObject.hasSetter(CREATEUSER_NAMEINBEAN); ? ? ? ?if (createUser) { ? ? ? ? ? ?this.strictInsertFill(metaObject, CREATEUSER_NAMEINBEAN, String.class, "admin"); ? ? ? } ? ? ? ?boolean createTime = metaObject.hasSetter(CREATETIME_NAMEINBEAN); ? ? ? ?if (createTime) { ? ? ? ? ? ?this.strictInsertFill(metaObject, CREATETIME_NAMEINBEAN, LocalDateTime.class, LocalDateTime.now()); ? ? ? } ? ? ? ?boolean updateUser = metaObject.hasSetter(UPDATEUSER_NAMEINBEAN); ? ? ? ?if (updateUser) { ? ? ? ? ? ?this.strictInsertFill(metaObject, UPDATEUSER_NAMEINBEAN, String.class, "admin"); ? ? ? } ? ? ? ?boolean updateTime = metaObject.hasSetter(UPDATETIME_NAMEINBEAN); ? ? ? ?if (updateTime) { ? ? ? ? ? ?this.strictInsertFill(metaObject, UPDATETIME_NAMEINBEAN, LocalDateTime.class, LocalDateTime.now()); ? ? ? } ? }? ? ?@Override ? ?public void updateFill(MetaObject metaObject) { ? ? ? ?boolean updateUser = metaObject.hasSetter(UPDATEUSER_NAMEINBEAN); ? ? ? ?if (updateUser) { ? ? ? ? ? ?this.strictInsertFill(metaObject, UPDATEUSER_NAMEINBEAN, String.class, "amdin"); ? ? ? } ? ? ? ?boolean updateTime = metaObject.hasSetter(UPDATETIME_NAMEINBEAN); ? ? ? ?if (updateTime) { ? ? ? ? ? ?this.strictInsertFill(metaObject, UPDATETIME_NAMEINBEAN, LocalDateTime.class, LocalDateTime.now()); ? ? ? } ? }}?
- 測試
@Testvoid update() { // 更新id為2角色的名字為測試2 Role role = new Role(); role.setName("測試2"); role.setId("2"); roleMapper.updateById(role);}

在執行更新操作時自動加上更新人和更新時間
枚舉類型處理器
自mybatis3.1.0開始,如果你無需使用原生枚舉,可配置默認枚舉來省略掃描通用枚舉配置 默認枚舉配置
- 定義枚舉類,主要有兩種方式
方法一:采用繼承IEnum實現
@Getter@AllArgsConstructorpublic enum RoleType implements IEnum { ADMIN("1"), COMMON("2"); private String type; @Override public Serializable getValue() { return type; }}
方法二:注解方式,在枚舉類需要解析的屬性上增加@EnumValue注解
@Getter@AllArgsConstructorpublic enum RoleType { ADMIN("1"), COMMON("2"); @EnumValue//標記數據庫存的值是type private String type;}
- 定義實體類
@Data@TableName("sys_role")public class Role { /** 角色類型 */ private RoleType type;}
- 配置掃描的枚舉包路徑
mybatis-plus: typeEnumsPackage: com.yanyu.spring.mybatisplus.enums

從結果可以看出查詢出的角色類型自動轉換成了枚舉ADMIN
Sql注入
當Mybatis-plus自帶的原生方法不能滿足我們的需求,我們可以利用sql注入器自定義sql
實現步驟:
- 創建自定義的類
public class DeleteByCodeMethod extends AbstractMethod { @Override public MappedStatement injectMappedStatement(Class> mapperClass, Class> modelClass, TableInfo tableInfo) { // 執行的slq String sql = "delete from "+ tableInfo.getTableName() +" where code = #{code}"; // Mapper接口方法名 String method = "deleteByCode"; SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass); return addDeleteMappedStatement(mapperClass, method, sqlSource); }}
- 創建注入器
@Componentpublic class MySqlInject extends DefaultSqlInjector { @Override public List getMethodList(Class> mapperClass) { List methodList = super.getMethodList(mapperClass); methodList.add(new DeleteByCodeMethod()); return methodList; }}
- 在Mapper中加入自定義方法
public interface RoleMapper extends BaseMapper { int deleteByCode(@Param("code") String code);}
- 測試
@Testvoid deleteByCode() { // 刪除編碼為code的角色 roleMapper.deleteByCode("test");}

從結果看,我們自定義的根據編碼刪除數據執行成功
Mybatis-plus官方為我們提供了三種自定義類
- InsertBatchSomeColumn:批量新增數據,自選字段insert
- AlwaysUpdateSomeColumnById:根據id更新固定字段
- LogicDeleteByIdWithFill:根據id邏輯刪除,并帶字段填充功能
以InsertBatchSomeColumn為例,簡單的演示一下怎么使用
- 在注入器中加入InsertBatchSomeColumn自定義類
@Componentpublic class MySqlInject extends DefaultSqlInjector { @Override public List getMethodList(Class> mapperClass) { List methodList = super.getMethodList(mapperClass); methodList.add(new DeleteByCodeMethod()); /** * 不是邏輯刪除的字段包括在內 */ methodList.add(new InsertBatchSomeColumn(t -> !t.isLogicDelete())); return methodList; }}
- 在Mapper中加入自定義方法
public interface RoleMapper extends BaseMapper { int insertBatchSomeColumn(List list);}
- 測試
@Testvoid insertBatchSomeColumn() { // 測試批量插入角色1和角色2 Role role1 = new Role(); role1.setCode("ROLE_1"); role1.setName("角色1"); role1.setType(RoleType.ADMIN); Role role2 = new Role(); role2.setCode("ROLE_2"); role2.setName("角色2"); role2.setType(RoleType.ADMIN); List roles = new ArrayList<>(Arrays.asList(role1,role2)); roleMapper.insertBatchSomeColumn(roles);}

多租戶
租戶實現
Mybatis-plus多租戶依賴于分頁插件,下面我們將簡單介紹如何實現租戶解析
- 定義租戶解析器
@Beanpublic PaginationInterceptor paginationInterceptor() throws IOException { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); TenantSqlParser tenantSqlParser = new TenantSqlParser(); tenantSqlParser.setTenantHandler(new TenantHandler() { @Override public Expression getTenantId(boolean select) { return new StringValue("00000"); } @Override public String getTenantIdColumn() { return "tenant_code"; } @Override public boolean doTableFilter(String tableName) { /** * 是否加租戶信息,false->加,true->不加 */ return false; } }); paginationInterceptor.setSqlParserList(Arrays.asList(tenantSqlParser)); return paginationInterceptor;}
- 測試
@Testpublic void tenant() { // 查詢id為1的角色 roleMapper.selectById("1");}

從結果看,sql執行時在查詢條件中自動為我們加上了租戶判斷
特定sql過濾
在開發中有的方法不需要限定租戶標識,實現方式有兩種
- 方式一:通過在分頁插件中自定義過濾器,具體實現如下所示
@Beanpublic PaginationInterceptor paginationInterceptor() throws IOException { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); TenantSqlParser tenantSqlParser = new TenantSqlParser(); tenantSqlParser.setTenantHandler(new TenantHandler() { @Override public Expression getTenantId(boolean select) { return new StringValue("00000"); } @Override public String getTenantIdColumn() { return "tenant_code"; } @Override public boolean doTableFilter(String tableName) { /** * 是否加租戶信息,false->加,true->不加 */ return false; } }); paginationInterceptor.setSqlParserList(Arrays.asList(tenantSqlParser)); paginationInterceptor.setSqlParserFilter(new ISqlParserFilter() { /** * true 不增加,false 增加 * @param metaObject * @return */ @Override public boolean doFilter(MetaObject metaObject) { MappedStatement ms = SqlParserHelper.getMappedStatement(metaObject); if("具體方法".equals(ms.getId())) { return true; } return false; } }); return paginationInterceptor;}
- 方式二:在不需要限定租戶的方法上加入
public interface RoleMapper extends BaseMapper { @SqlParser(filter = true) int getByCode(String code);}
如果有哪里寫得不對的,還請各位小友指正,只有不斷試錯,才能慢慢提高。如果你覺得對你有幫助,請點贊+關注,謝謝!!!!!!