【Mybatis-Plus】连表查询 逻辑删除 多租户

news/2024/12/24 3:00:51 标签: MybatisPlus, java, spring boot

文章目录

    • 连表查询
    • 逻辑删除
    • 多租户

连表查询

引入 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

java">public interface RoleMapper extends MPJBaseMapper<Role> {}

public interface UserMapper extends MPJBaseMapper<User> {
    public UserRole findUserRole();
}

观察源码,MPJBaseMapper 继承了 BaseMapper,并添加了连表查询的功能。

java">public interface MPJBaseMapper<T> extends BaseMapper<T>, JoinMapper<T> {}

定义一个 JavaBean 存储用户和角色信息的组合。包含用户 ID (id)、角色 ID (rid)、用户名 (userName) 和角色名 (roleName)。

java">@Data
public class UserRole {
    private Integer id;
    private Integer rid;
    private String userName;
    private String roleName;
}

分别通过 MPJLambdaWrapperMPJQueryWrapper 来构建查询,获取包含用户和角色信息的 UserRole 对象列表。

java">@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();
    }
}
java">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>
java">@SpringBootTest
class UserMapperTest {
    @Resource
    private UserMapper userMapper;
    @Test
    public void mpj(){
        userMapper.findUserRole();
    }
}

逻辑删除

逻辑删除是一种优雅的数据管理策略,它通过在数据库中标记记录为“已删除”而非物理删除,来保留数据的历史痕迹,同时确保查询结果的整洁性。MyBatis-Plus 提供了便捷的逻辑删除支持,使得这一策略的实施变得简单高效。

MyBatis-Plus 的逻辑删除功能会在执行数据库操作时自动处理逻辑删除字段。以下是它的工作方式:

  • 插入:逻辑删除字段的值不受限制。
  • 查找:自动添加条件,过滤掉标记为已删除的记录。
  • 更新:防止更新已删除的记录。
  • 删除:将删除操作转换为更新操作,标记记录为已删除。

例如:

  • 删除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 注解

在这里插入图片描述

确保数据库表中已添加了逻辑删除字段,并设置默认值为逻辑未删除值。在实体类中,对应数据库表的逻辑删除字段上添加 @TableLogic 注解。

java">import com.baomidou.mybatisplus.annotation.TableLogic;
public class User {
    @TableLogic
    private Integer isdeleted;
}

3、测试

java">@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);
    }
}
java">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
<==    ...

再测试一下删除

java">@Test
public void delete() {
    providerService.removeById(17);
}
java">==>  Preparing: UPDATE smbms_provider SET isdeleted=1 WHERE id=? AND isdeleted=0
==> Parameters: 17(Integer)
<==    Updates: 1

公共实体类(Common Entity Class)将多个实体类共有的属性和行为封装到一个单独的类中。

java">@Data
@TableName("smbms_provider")
public class Provider extends BaseEntity{
	// 数据库自增 ID 作为主键
	@TableId(value = "id", type = IdType.AUTO)
	private Integer id;   //id
	private String proCode; //供应商编码
	// 映射到数据库字段 proName as pname
	@TableField("proName")
	private String pname; //供应商名称
	private String proDesc; //供应商描述
	private String proContact; //供应商联系人
	private String proPhone; //供应商电话
	private String proAddress; //供应商地址
	private String proFax; //供应商传真
}
java">@Data
public class BaseEntity implements Serializable {
    private Integer createdBy; //创建者
    private String creationDate; //创建时间
    private Integer modifyBy; //更新者
    private String modifyDate;//更新时间
    @TableLogic
    private Integer isdeleted;
}

多租户

MyBatis-Plus 提供了 TenantLineInnerInterceptor 插件用于实现多租户的数据隔离。通过这个插件,可以确保每个租户只能访问自己的数据,从而实现数据的安全隔离。

关键属性

属性名类型默认值描述
tenantLineHandlerTenantLineHandler租户处理器( 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));
    }
}

使用一下,先定义一个实现类 CustomTenantHandle 继承 TenantLineHandler 接口

java">@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; // 拼接
    }
}

多租户数据库中,不同租户的数据存储在同一张表中,通过租户ID来区分。分页查询结合租户过滤条件可以确保每个租户只能访问到自己的数据。另外,分页也可以限制查询结果的数量,从而提高查询效率。

java">@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;
    }
}

测试一下

java">@Test
public void findpage() {
    Page<Provider> page = new Page<>(1,5);
    providerService.page(page,null);
}

查询到 4 条记录

java">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)
<== ...

http://www.niftyadmin.cn/n/5797248.html

相关文章

VSCode 中 Git 功能比较:内置 Git、GitLens 与 Git History 插件

在软件开发领域&#xff0c;版本控制是维护代码变更的重要工具。Git 作为最流行的版本控制系统&#xff0c;被广泛集成在各种代码编辑器中。Visual Studio Code&#xff08;VSCode&#xff09;不仅内置了 Git 支持&#xff0c;还提供了丰富的扩展来增强 Git 功能。本文将对比 V…

SQL 使用带聚集函数的联结

聚集函数用于汇总数据&#xff0c;通常用于从一个表中计算统计信息&#xff0c;但也可以与联结一起使用。以下是一个例子&#xff0c;展示如何使用聚集函数统计每个顾客的订单数。 示例 1&#xff1a;使用 COUNT() 函数与 INNER JOIN 假设我们需要检索所有顾客及每个顾客所下…

AI开发:使用支持向量机(SVM)进行文本情感分析训练 - Python

支持向量机是AI开发中最常见的一种算法。之前我们已经一起初步了解了它的概念和应用&#xff0c;今天我们用它来进行一次文本情感分析训练。 一、概念温习 支持向量机&#xff08;SVM&#xff09;是一种监督学习算法&#xff0c;广泛用于分类和回归问题。 它的核心思想是通过…

深度学习中的MSE与MAE

有空再把内容补上来 均方误差&#xff08;Mean Squared Error&#xff0c;MSE&#xff09;和平均绝对误差&#xff08;Mean Absolute Error&#xff0c;MAE&#xff09;是深度学习中常用的两种损失函数&#xff0c;用于衡量模型预测结果与真实标签之间的差异&#xff0c;以下是…

robots协议

robots协议&#xff0c;也称为爬虫协议、爬虫规则、机器人协议等&#xff0c;其全称是“网络爬虫排除标准”&#xff08;Robots Exclusion Protocol&#xff09;。以下是对robots协议的详细介绍&#xff1a; 一、定义与功能 robots协议是指网站可以建立一个名为robots.txt的文…

我的个人博客正式上线了!

我的个人博客终于上线啦点此访问 经过一番折腾&#xff0c;我的个人博客终于上线啦&#xff01;这是一个属于我自己的小天地&#xff0c;可以用来记录生活点滴、技术分享以及一些随想。 在这里&#xff0c;我想分享一下搭建博客的整个过程和心得体会。 为什么要搭建博客&…

与乐鑫相约 CES 2025|创新技术引领物联网与嵌入式未来

2025 国际消费电子产品展览会 (International Consumer Electronics Show, CES) 将于 2025 年 1 月 7 至 10 日在美国拉斯维加斯盛大开幕。作为全球规模最大、水准最高&#xff0c;且影响力最广的消费电子类科技盛会&#xff0c;CES 每年都吸引着全球行业领袖、开发者和技术爱好…

【计算机视觉基础CV-图像分类】02-入门详解图像分类、经典数据集、比赛与冠军图像模型演进史

前言 图像分类&#xff08;Image Classification&#xff09;是计算机视觉&#xff08;Computer Vision&#xff09;中一项基础且核心的任务。简单来说&#xff0c;就是让计算机从给定的类别集合中&#xff0c;为一张输入图片分配一个正确的类别标签。这个过程听起来直观&…