探索MyBatis-Plus的高阶用法

引言

MyBatis-Plus 是 MyBatis 的增强工具包,提供了许多方便快捷的功能来简化开发,提高效率。除了基本的 CRUD 操作外,MyBatis-Plus 还提供了一些高级功能,本文将探讨 MyBatis-Plus 的高阶用法,帮助开发者更好地利用该工具包。

1. 动态表名和字段

MyBatis-Plus 支持动态表名和字段,这在一些特殊场景下非常有用,比如多租户系统或者动态数据源切换。通过注解 @TableName@TableField 可以动态指定表名和字段名。

@TableName("user_${dynamicValue}")
public class User {
    @TableField(value = "name_${dynamicValue}")
    private String name;
}

2. 自定义全局操作

MyBatis-Plus 允许自定义全局操作,比如自定义全局的查询条件、插入前操作、更新前操作等。通过实现 com.baomidou.mybatisplus.core.injector.ISqlInjector 接口可以实现自定义 SQL 注入器,通过实现 com.baomidou.mybatisplus.core.handlers.MetaObjectHandler 接口可以实现字段自动填充等。

@Component
public class CustomMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, "createTime", LocalDateTime::now, LocalDateTime.class);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime::now, LocalDateTime.class);
    }
}

3. 自动分页

MyBatis-Plus 提供了自动分页的功能,可以自动根据查询条件进行分页,无需手动编写分页 SQL。只需在查询条件中添加分页参数即可。

Page<User> page = new Page<>(1, 10);
userMapper.selectPage(page, null);

4. 逻辑删除

MyBatis-Plus 支持逻辑删除,通过注解 @TableLogic 可以指定逻辑删除字段,并在查询时自动过滤掉已被逻辑删除的记录。

@Configuration
@MapperScan("com.example.mapper")
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new LogicSqlInjector());
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

    @Bean
    public ISqlInjector sqlInjector() {
        return new LogicSqlInjector();
    }
}
@TableLogic
@TableField(value = "is_deleted")
private Integer deleted;
// 执行逻辑删除
userMapper.deleteById(userId);

// 查询用户列表,自动过滤已被逻辑删除的记录
List<User> userList = userMapper.selectList(null);

5. 实现多租户系统

在多租户系统中,不同的租户需要访问不同的数据,但数据结构相同。通过动态表名可以很方便地实现多租户数据的隔离存储。

@TableName("user_${tenantId}")
public class User {
    @TableField(value = "name")
    private String name;
}

根据不同的租户(tenantId),用户数据将存储在不同的表中,实现了多租户数据的隔离存储。 

 

6. 动态数据源切换

在一些特殊的场景中,需要根据不同的条件切换数据源。通过动态表名和字段可以很方便地实现动态数据源切换。

@TableName("user_${dataSource}")
public class User {
    @TableField(value = "name_${dynamicValue}")
    private String name;
}

7. 数据权限控制

在一些需要进行数据权限控制的系统中,不同的用户可能只能访问部分数据。通过动态表名和字段可以很方便地实现数据权限控制。

@TableName("user_${roleId}")
public class User {
    @TableField(value = "name_${dynamicValue}")
    private String name;
}

根据不同的用户角色(roleId),用户数据将存储在不同的表中,并且字段名也会动态变化,实现数据权限控制的需求。 

 

8. 分表分库

在数据量较大的系统中,为了提高性能和扩展性,可能会采用分表分库的方式来存储数据。通过动态表名和字段可以很方便地实现分表分库。

@TableName("user_${shardingValue}")
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String username;
    private Integer age;
    // 其他字段...
}

 分库分表策略配置

@Configuration
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 配置分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        // 配置分片插件
        interceptor.addInnerInterceptor(new DynamicTableNameInnerInterceptor());
        return interceptor;
    }

    @Bean
    public DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor() {
        return new DynamicTableNameInnerInterceptor();
    }
}

分库分表策略实现 

public class DynamicTableNameInnerInterceptor extends InnerInterceptor {
    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        if (parameter instanceof Map) {
            Map<?, ?> paramMap = (Map<?, ?>) parameter;
            ShardingValue shardingValue = (ShardingValue) paramMap.get("shardingValue");
            if (shardingValue != null) {
                String tableName = "user_" + shardingValue.getValue() % 2; // 根据分片值计算表名
                String sql = boundSql.getSql().replaceFirst("user", tableName); // 替换原始 SQL 中的表名
                ReflectionUtils.setField(boundSql, "sql", sql); // 修改 BoundSql 中的 SQL
            }
        }
    }
}

9. 动态 SQL

在一些复杂的业务场景中,可能需要根据不同的条件动态生成 SQL,比如动态拼接 WHERE 子句、动态排序等。MyBatis-Plus 提供了方便的 API 来实现动态 SQL。

QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("status", status);
if (StringUtils.isNotBlank(keyword)) {
    wrapper.like("name", keyword);
}
wrapper.orderByDesc("create_time");
List<User> userList = userMapper.selectList(wrapper);

10. 乐观锁

在并发场景下,为了保证数据的一致性,可能会使用乐观锁机制来控制并发访问。MyBatis-Plus 提供了乐观锁的支持,通过 @Version 注解标注实体类中的版本字段即可实现乐观锁功能。

@Version
@TableField(value = "version")
private Integer version;

11. 逻辑分页

在一些特殊的场景中,可能需要进行复杂的分页操作,比如根据某个字段的范围进行分页查询。MyBatis-Plus 提供了逻辑分页的功能,通过 last() 方法可以实现自定义的分页逻辑。根据年龄大于等于 18 并按照创建时间降序排列的条件进行分页查询

IPage<User> page = new Page<>(1, 10);
userMapper.selectPage(page, Wrappers.<User>lambdaQuery()
    .ge(User::getAge, 18)
    .orderByDesc(User::getCreateTime)
    .last("limit 10"));

12. 代码生成器        

public class CodeGenerator {

    public static void main(String[] args) {
        AutoGenerator generator = new AutoGenerator();
        // 配置数据源、包配置、策略配置等
        generator.execute();
    }
}

结语

MyBatis-Plus 是一个非常优秀的 MyBatis 增强工具包,它在简化开发、提高效率、提升性能等方面都有着显著的优势,是开发中不可或缺的利器。希望本文对读者对 MyBatis-Plus 的了解有所帮助,欢迎大家深入学习和使用 MyBatis-Plus。

 

更多文章


​​Spring中的事务是如何实现的-CSDN博客

ZooKeeper 使用介绍和原理详解-CSDN博客

Redis集群选举流程详解-CSDN博客

Hadoop技术解析:分布式存储与计算-CSDN博客

ES底层原理深度剖析_es 的底层原理-CSDN博客

 

  • 30
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Memory_2020

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值