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 來構(gòu)建查詢,獲取包含用戶和角色信息的 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 語句
這種方式可以提供更細(xì)粒度的控制,并且使得 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ù)據(jù)管理策略,它通過在數(shù)據(jù)庫中標(biāo)記記錄為“已刪除”而非物理刪除,來保留數(shù)據(jù)的歷史痕跡,同時確保查詢結(jié)果的整潔性。MyBatis-Plus 提供了便捷的邏輯刪除支持,使得這一策略的實施變得簡單高效。
MyBatis-Plus 的邏輯刪除功能會在執(zhí)行數(shù)據(jù)庫操作時自動處理邏輯刪除字段。以下是它的工作方式:
- 插入:邏輯刪除字段的值不受限制。
- 查找:自動添加條件,過濾掉標(biāo)記為已刪除的記錄。
- 更新:防止更新已刪除的記錄。
- 刪除:將刪除操作轉(zhuǎn)換為更新操作,標(biāo)記記錄為已刪除。
例如:
- 刪除:
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ù)據(jù)庫表中已添加了邏輯刪除字段,并設(shè)置默認(rèn)值為邏輯未刪除值。在實體類中,對應(yīng)數(shù)據(jù)庫表的邏輯刪除字段上添加 @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ù)據(jù)庫自增 ID 作為主鍵
@TableId(value = "id", type = IdType.AUTO)
private Integer id; //id
private String proCode; //供應(yīng)商編碼
// 映射到數(shù)據(jù)庫字段 proName as pname
@TableField("proName")
private String pname; //供應(yīng)商名稱
private String proDesc; //供應(yīng)商描述
private String proContact; //供應(yīng)商聯(lián)系人
private String proPhone; //供應(yīng)商電話
private String proAddress; //供應(yīng)商地址
private String proFax; //供應(yīng)商傳真
}@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ù)據(jù)隔離。通過這個插件,可以確保每個租戶只能訪問自己的數(shù)據(jù),從而實現(xiàn)數(shù)據(jù)的安全隔離。
關(guān)鍵屬性
| 屬性名 | 類型 | 默認(rèn)值 | 描述 |
|---|---|---|---|
| tenantLineHandler | TenantLineHandler | 租戶處理器( TenantId 行級 ) |
TenantLineHandler 接口定義了以下方法:
public interface TenantLineHandler {
/**
* 獲取租戶 ID 值表達(dá)式,只支持單個 ID 值
*
* @return 租戶 ID 值表達(dá)式
*/
Expression getTenantId();
/**
* 獲取租戶字段名
* 默認(rèn)字段名叫: tenant_id
*
* @return 租戶字段名
*/
default String getTenantIdColumn() {
return "tenant_id";
}
/**
* 根據(jù)表名判斷是否忽略拼接多租戶條件
* 默認(rèn)都要進(jìn)行解析并拼接多租戶條件
*
* @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ù)據(jù)庫中,不同租戶的數(shù)據(jù)存儲在同一張表中,通過租戶ID來區(qū)分。分頁查詢結(jié)合租戶過濾條件可以確保每個租戶只能訪問到自己的數(shù)據(jù)。另外,分頁也可以限制查詢結(jié)果的數(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) <== ...
到此這篇關(guān)于MybatisPlus 連表查詢、邏輯刪除功能實現(xiàn)(多租戶)的文章就介紹到這了,更多相關(guān)MybatisPlus 邏輯刪除內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringApplicationRunListener監(jiān)聽器源碼詳解
這篇文章主要介紹了SpringApplicationRunListener監(jiān)聽器源碼詳解,springboot提供了兩個類SpringApplicationRunListeners、SpringApplicationRunListener(EventPublishingRunListener),spring框架還提供了一個ApplicationListener接口,需要的朋友可以參考下2023-11-11
Spring?MVC和springboot靜態(tài)資源處理問題
這篇文章主要介紹了Spring?MVC和springboot靜態(tài)資源處理問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08
spring @Scheduled定時任務(wù)注解使用方法及注意事項小結(jié)
Spring的@Scheduled注解用于定時任務(wù)調(diào)度,默認(rèn)單線程依次執(zhí)行,可以通過配置多線程調(diào)度器或使用@Async注解實現(xiàn)并行執(zhí)行,常見參數(shù)包括cron、fixedRate、fixedDelay、initialDelay等,本文介紹spring @Scheduled定時任務(wù)注解使用方法,感興趣的朋友一起看看吧2025-02-02

