MybatisPlus 連表查詢、邏輯刪除功能實現(xiàn)(多租戶)
連表查詢
引入 mybatis-plus-join-boot-starter
依賴
<dependency> <groupId>com.github.yulichang</groupId> <artifactId>mybatis-plus-join-boot-starter</artifactId> <version>1.5.1</version> </dependency>
繼承 MPJBaseMapper
public interface RoleMapper extends MPJBaseMapper<Role> {} public interface UserMapper extends MPJBaseMapper<User> { public UserRole findUserRole(); }
觀察源碼,MPJBaseMapper 繼承了 BaseMapper,并添加了連表查詢的功能。
public interface MPJBaseMapper<T> extends BaseMapper<T>, JoinMapper<T> {}
定義一個 JavaBean 存儲用戶和角色信息的組合。包含用戶 ID (id
)、角色 ID (rid
)、用戶名 (userName
) 和角色名 (roleName
)。
@Data public class UserRole { private Integer id; private Integer rid; private String userName; private String roleName; }
分別通過 MPJLambdaWrapper
和 MPJQueryWrapper
來構建查詢,獲取包含用戶和角色信息的 UserRole
對象列表。
@SpringBootTest class UserMapperTest { @Resource private UserMapper userMapper; @Test public void mpj(){ MPJLambdaWrapper<User> lambdaWrapper = JoinWrappers.lambda(User.class) .select(User::getId,User::getUserName) .selectAs(Role::getId,UserRole::getRid) .select(Role::getRoleName) .leftJoin(Role.class,Role::getId,User::getUserRole); List<UserRole> userRoleList = userMapper.selectJoinList(UserRole.class, lambdaWrapper); userMapper.findUserRole(); } }
MPJQueryWrapper<User> queryWrapper = new MPJQueryWrapper<>(); queryWrapper.select("t.id,userName,t1.id as rid,roleName"); queryWrapper.leftJoin("smbms_role t1 on t.userRole = t1.id"); List<UserRole> userRoleList = userMapper.selectJoinList(UserRole.class, queryWrapper); userMapper.findUserRole();
以上兩種方式較少使用,最常用的還是使用 XML 文件來編寫 SQL 語句
這種方式可以提供更細粒度的控制,并且使得 SQL 語句更加集中和清晰。
<mapper namespace="com.hz.mapper.UserMapper"> <select id="findUserRole" resultType="com.hz.pojo.dto.userRole"> SELECT t.id,userName,t1.id as rid,roleName FROM smbms_user t LEFT JOIN smbms_role t1 on t.userRole = t1.id </select> </mapper>
@SpringBootTest class UserMapperTest { @Resource private UserMapper userMapper; @Test public void mpj(){ userMapper.findUserRole(); } }
邏輯刪除
邏輯刪除是一種優(yōu)雅的數(shù)據管理策略,它通過在數(shù)據庫中標記記錄為“已刪除”而非物理刪除,來保留數(shù)據的歷史痕跡,同時確保查詢結果的整潔性。MyBatis-Plus 提供了便捷的邏輯刪除支持,使得這一策略的實施變得簡單高效。
MyBatis-Plus 的邏輯刪除功能會在執(zhí)行數(shù)據庫操作時自動處理邏輯刪除字段。以下是它的工作方式:
- 插入:邏輯刪除字段的值不受限制。
- 查找:自動添加條件,過濾掉標記為已刪除的記錄。
- 更新:防止更新已刪除的記錄。
- 刪除:將刪除操作轉換為更新操作,標記記錄為已刪除。
例如:
- 刪除:
update user set deleted=1 where id = 1 and deleted=0
- 查找:
select id,name,deleted from user where deleted=0
使用步驟
1、配置全局屬性
在 application.yml
中配置 MyBatis-Plus 的全局邏輯刪除屬性。
mybatis-plus: global-config: db-config: logic-delete-field: isdeleted # 全局邏輯刪除字段名 logic-delete-value: 1 # 邏輯已刪除值 logic-not-delete-value: 0 # 邏輯未刪除值
2、使用 @TableLogic 注解
確保數(shù)據庫表中已添加了邏輯刪除字段,并設置默認值為邏輯未刪除值。在實體類中,對應數(shù)據庫表的邏輯刪除字段上添加 @TableLogic
注解。
import com.baomidou.mybatisplus.annotation.TableLogic; public class User { @TableLogic private Integer isdeleted; }
3、測試
@SpringBootTest public class ProviderServiceImplTest { @Resource private ProviderService providerService; @Test public void find() { QueryWrapper<Provider> queryWrapper = new QueryWrapper<>(); queryWrapper.select("id", "proCode", "proDesc", "proName"); providerService.list(queryWrapper); } }
JDBC Connection [HikariProxyConnection@23218037 wrapping com.mysql.cj.jdbc.ConnectionImpl@1e7f19b4] will not be managed by Spring ==> Preparing: SELECT id,proCode,proDesc,proName FROM smbms_provider WHERE isdeleted=0 ==> Parameters: <== Columns: id, proCode, proDesc, proName <== ...
再測試一下刪除
@Test public void delete() { providerService.removeById(17); }
==> Preparing: UPDATE smbms_provider SET isdeleted=1 WHERE id=? AND isdeleted=0 ==> Parameters: 17(Integer) <== Updates: 1
公共實體類(Common Entity Class)將多個實體類共有的屬性和行為封裝到一個單獨的類中。
@Data @TableName("smbms_provider") public class Provider extends BaseEntity{ // 數(shù)據庫自增 ID 作為主鍵 @TableId(value = "id", type = IdType.AUTO) private Integer id; //id private String proCode; //供應商編碼 // 映射到數(shù)據庫字段 proName as pname @TableField("proName") private String pname; //供應商名稱 private String proDesc; //供應商描述 private String proContact; //供應商聯(lián)系人 private String proPhone; //供應商電話 private String proAddress; //供應商地址 private String proFax; //供應商傳真 }
@Data public class BaseEntity implements Serializable { private Integer createdBy; //創(chuàng)建者 private String creationDate; //創(chuàng)建時間 private Integer modifyBy; //更新者 private String modifyDate;//更新時間 @TableLogic private Integer isdeleted; }
多租戶
MyBatis-Plus 提供了 TenantLineInnerInterceptor
插件用于實現(xiàn)多租戶的數(shù)據隔離。通過這個插件,可以確保每個租戶只能訪問自己的數(shù)據,從而實現(xiàn)數(shù)據的安全隔離。
關鍵屬性
屬性名 | 類型 | 默認值 | 描述 |
---|---|---|---|
tenantLineHandler | TenantLineHandler | 租戶處理器( TenantId 行級 ) |
TenantLineHandler
接口定義了以下方法:
public interface TenantLineHandler { /** * 獲取租戶 ID 值表達式,只支持單個 ID 值 * * @return 租戶 ID 值表達式 */ Expression getTenantId(); /** * 獲取租戶字段名 * 默認字段名叫: tenant_id * * @return 租戶字段名 */ default String getTenantIdColumn() { return "tenant_id"; } /** * 根據表名判斷是否忽略拼接多租戶條件 * 默認都要進行解析并拼接多租戶條件 * * @param tableName 表名 * @return 是否忽略, true:表示忽略,false:需要解析并拼接多租戶條件 */ default boolean ignoreTable(String tableName) { return false; } /** * 忽略插入租戶字段邏輯 * * @param columns 插入字段 * @param tenantIdColumn 租戶 ID 字段 * @return */ default boolean ignoreInsert(List<Column> columns, String tenantIdColumn) { return columns.stream().map(Column::getColumnName).anyMatch(i -> i.equalsIgnoreCase(tenantIdColumn)); } }
使用一下,先定義一個實現(xiàn)類 CustomTenantHandle
繼承 TenantLineHandler
接口
@Component public class CustomTenantHandler implements TenantLineHandler { @Override public Expression getTenantId() { int userId = 2; return new LongValue(userId); } @Override public String getTenantIdColumn() { return "createdBy"; } @Override public boolean ignoreTable(String tableName) { return false; // 拼接 } }
多租戶數(shù)據庫中,不同租戶的數(shù)據存儲在同一張表中,通過租戶ID來區(qū)分。分頁查詢結合租戶過濾條件可以確保每個租戶只能訪問到自己的數(shù)據。另外,分頁也可以限制查詢結果的數(shù)量,從而提高查詢效率。
@Configuration public class MybatisPlusConfig { @Resource private CustomTenantHandler customTenantHandler; @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 多租戶 TenantLineInnerInterceptor tenantInterceptor = new TenantLineInnerInterceptor(); tenantInterceptor.setTenantLineHandler(customTenantHandler); interceptor.addInnerInterceptor(tenantInterceptor); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }
測試一下
@Test public void findpage() { Page<Provider> page = new Page<>(1,5); providerService.page(page,null); }
查詢到 4 條記錄
JDBC Connection [HikariProxyConnection@227080339 wrapping com.mysql.cj.jdbc.ConnectionImpl@259b85d6] will not be managed by Spring ==> Preparing: SELECT COUNT(*) AS total FROM smbms_provider WHERE isdeleted = 0 AND smbms_provider.createdBy = 2 ==> Parameters: <== Columns: total <== Row: 4 <== Total: 1 ==> Preparing: SELECT id, proCode, proName AS pname, proDesc, proContact, proPhone, proAddress, proFax, createdBy, creationDate, modifyBy, modifyDate, isdeleted FROM smbms_provider WHERE isdeleted = 0 AND smbms_provider.createdBy = 2 LIMIT ? ==> Parameters: 5(Long) <== ...
到此這篇關于MybatisPlus 連表查詢、邏輯刪除功能實現(xiàn)(多租戶)的文章就介紹到這了,更多相關MybatisPlus 邏輯刪除內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringApplicationRunListener監(jiān)聽器源碼詳解
這篇文章主要介紹了SpringApplicationRunListener監(jiān)聽器源碼詳解,springboot提供了兩個類SpringApplicationRunListeners、SpringApplicationRunListener(EventPublishingRunListener),spring框架還提供了一個ApplicationListener接口,需要的朋友可以參考下2023-11-11Spring?MVC和springboot靜態(tài)資源處理問題
這篇文章主要介紹了Spring?MVC和springboot靜態(tài)資源處理問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08spring @Scheduled定時任務注解使用方法及注意事項小結
Spring的@Scheduled注解用于定時任務調度,默認單線程依次執(zhí)行,可以通過配置多線程調度器或使用@Async注解實現(xiàn)并行執(zhí)行,常見參數(shù)包括cron、fixedRate、fixedDelay、initialDelay等,本文介紹spring @Scheduled定時任務注解使用方法,感興趣的朋友一起看看吧2025-02-02