当前位置: 首页 > news >正文

MyBatis-Flex 来了

前言

MyBatis-Flex 是一个优雅的 MyBatis 增强框架,它非常轻量、同时拥有极高的性能与灵活性。我们可以轻松的使用 Mybaits-Flex 链接任何数据库,其内置的 QueryWrapper亮点 帮助我们极大的减少了 SQL 编写的工作的同时,减少出错的可能性。

更轻量

MyBatis-Flex 除了 MyBatis 本身,再无任何第三方依赖,因此会带来更高的自主性、把控性和稳定性。在任何一个系统中,依赖越多,稳定性越差。

更灵活

MyBatis-Flex 提供了非常灵活的 QueryWrapper,支持关联查询、多表查询、多主键、逻辑删除、乐观锁更新、数据填充、数据脱敏、等等....

更高的性能

MyBatis-Flex 通过独特的架构,没有任何 MyBatis 拦截器、在 SQL 执行的过程中,没有任何的 SQL Parse,因此会带来指数级的性能增长。

功能对比

功能或特点

MyBatis-Flex

MyBatis-Plus

Fluent-MyBatis

对 entity 的基本增删改查 

✅ 

✅ 

✅ 

分页查询 

✅ 

✅ 

✅ 

分页查询之总量缓存 

✅ 

✅ 

❌ 

分页查询无 SQL 解析设计(更轻量,及更高性能) 

✅ 

❌ 

✅ 

多表查询:from 多张表 

✅ 

❌ 

❌ 

多表查询:left join、inner join 等等 

✅ 

❌ 

✅ 

多表查询:union,union all 

✅ 

❌ 

✅ 

单主键配置 

✅ 

✅ 

✅ 

多种 id 生成策略 

✅ 

✅ 

✅ 

支持多主键、复合主键 

✅ 

❌ 

❌ 

字段的 typeHandler 配置 

✅ 

✅ 

✅ 

除了 MyBatis,无其他第三方依赖(更轻量) 

✅ 

❌ 

❌ 

QueryWrapper 是否支持在微服务项目下进行 RPC 传输 

✅ 

❌ 

未知 

逻辑删除 

✅ 

✅ 

✅ 

乐观锁 

✅ 

✅ 

✅ 

SQL 审计 

✅ 

❌ 

❌ 

数据填充 

✅ 

✔️ (收费) 

✅ 

数据脱敏 

✅ 

✔️ (收费) 

❌ 

字段权限 

✅ 

✔️ (收费) 

❌ 

字段加密 

✅ 

✔️ (收费) 

❌ 

字典回写 

✅ 

✔️ (收费 

❌ 

Db + Row 

✅ 

❌ 

❌ 

Entity 监听 

✅ 

❌ 

❌ 

多数据源支持 

✅ 

借助其他框架或收费 

❌ 

多数据源是否支持 Spring 的事务管理,比如 @Transactional 和 TransactionTemplate 等 

✅ 

❌ 

❌ 

多数据源是否支持 "非Spring" 项目 

✅ 

❌ 

❌ 

多租户 

✅ 

✅ 

❌ 

动态表名 

✅ 

✅ 

❌ 

动态 Schema 

✅ 

❌ 

❌ 

性能对比
  • MyBatis-Flex 查询单条数据的速度,大概是 MyBatis-Plus 的 5 ~ 10+ 倍。

  • MyBatis-Flex 查询 10 条数据的速度,大概是 MyBatis-Plus 的 5~10 倍左右。

  • Mybatis-Flex 分页查询速度,大概是 Mybatis-Plus 的 5~10 倍左右。

  • Mybatis-Flex 数据更新速度,大概是 Mybatis-Plus 的 5~10+ 倍。

官网:https://mybatis-flex.com/

代码实践

除了Mybatis-plus带的那些功能,Mybatis-Flex提供了多主键、复合主键功能;提供了关联查询;特别是关联查询在日常业务开发碰到的场景很多。

Mybatis-Flex提供了一对一、一对多、多对一、多对多的场景。

1.添加依赖

<dependency><groupId>com.mybatis-flex</groupId><artifactId>mybatis-flex-spring-boot-starter</artifactId><version>1.5.3</version>
</dependency>
<dependency><groupId>com.mybatis-flex</groupId><artifactId>mybatis-flex-processor</artifactId><version>1.5.3</version>
</dependency>
<dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>8.0.31</version>
</dependency>
<dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId>
</dependency>
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional>
</dependency>

一对一关联查询 @RelationOneToOne

假设有一个账户,账户有身份证,账户和身份证的关系是一对一的关系,代码如下所示:

@Data
publicclassAccountimplementsSerializable {@Id(keyType = KeyType.Auto)private Long id;private String userName;@RelationOneToOne(selfField = "id", targetField = "accountId")private IDCard idCard;
}@Data
@Table(value = "tb_idcard")
publicclassIDCardimplementsSerializable {private Long accountId;private String cardNo;private String content;
}

若 selfField 是主键,且当前表只有 1 个主键时,可以不填写。因此,以上的配置可以简化为 @RelationOneToOne(targetField = "accountId")

执行sql:

SELECT `id`, `user_name`, `age` FROM `tb_account`SELECT `account_id`, `card_no`, `content` FROM `tb_idcard`
WHERE account_id IN(1, 2, 3, 4, 5)

结果打印:

[Account{id=1, userName='孙悟空', age=18, idCard=IDCard{accountId=1, cardNo='0001', content='内容1'}},Account{id=2, userName='猪八戒', age=19, idCard=IDCard{accountId=2, cardNo='0002', content='内容2'}},Account{id=3, userName='沙和尚', age=19, idCard=IDCard{accountId=3, cardNo='0003', content='内容3'}},Account{id=4, userName='六耳猕猴', age=19, idCard=IDCard{accountId=4, cardNo='0004', content='内容4'}},Account{id=5, userName='王麻子叔叔', age=19, idCard=IDCard{accountId=5, cardNo='0005', content='内容5'}}]

一对多关联查询 @RelationOneToMany

假设一个账户有很多本书籍,一本书只能归属一个账户所有;账户和书籍的关系是一对多的关系,代码如下:

@Data
publicclassAccountimplementsSerializable {@Id(keyType = KeyType.Auto)private Long id;private String userName;@RelationOneToMany(selfField = "id", targetField = "accountId")private List<Book> books;
}@Data
@Table(value = "tb_book")
publicclassBookimplementsSerializable {@Id(keyType = KeyType.Auto)private Long id;private Long accountId;private String title;
}

若 Account.books 是一个 Map,而非 List,那么,我们需要通过配置 mapKeyField 来指定列来充当 Map 的 Key, 如下代码所示:

@Data
publicclassAccountimplementsSerializable {@Id(keyType = KeyType.Auto)private Long id;private String userName;@RelationOneToMany(selfField = "id", targetField = "accountId", mapKeyField = "id")//使用 Book 的 id 来填充这个 map 的 keyprivate Map<Long, Book> books;
}

多对一关联查询 @RelationManyToOne

假设一个账户有很多本书籍,一本书只能归属一个账户所有;账户和书籍的关系是一对多的关系,书籍和账户的关系为多对一的关系,代码如下:

@Data
publicclassAccountimplementsSerializable {@Id(keyType = KeyType.Auto)private Long id;private String userName;
}@Data
@Table(value = "tb_book")
publicclassBookimplementsSerializable {@Id(keyType = KeyType.Auto)private Long id;private Long accountId;private String title;@RelationManyToOne(selfField = "accountId", targetField = "id")private Account account;
}

多对多关联查询 @RelationManyToMany

假设一个账户可以有多个角色,一个角色也可以有多个账户,他们是多对多的关系,需要通过中间表 tb_role_mapping 来维护:

@Data
publicclassAccountimplementsSerializable {@Id(keyType = KeyType.Auto)private Long id;private String userName;@RelationManyToMany(joinTable = "tb_role_mapping", // 中间表selfField = "id", joinSelfColumn = "account_id",targetField = "id", joinTargetColumn = "role_id")private List<Role> roles;
}@Data
@Table(value = "tb_role")
publicclassRoleimplementsSerializable {private Long id;private String name;
}

父子关系查询

@Data
@Table(value = "tb_menu")
publicclassMenuimplementsSerializable {private Long id;private Long parentId;private String name;@RelationOneToMany(selfField = "id", targetField = "parentId")private List<Menu> children;
}

在以上的父子关系查询中,默认的递归查询深度为 3 个层级,若需要查询指定递归深度,需要添加如下配置:

QueryWrapperqw= QueryWrapper.create();
qw.where(MENU.PARENT_ID.eq(0));//设置递归查询深度为 10 层
RelationManager.setMaxDepth(10);
List<Menu> menus = menuMapper.selectListWithRelationsByQuery(qw);

链式操作

在 MyBatis-Flex 中,内置了 QueryChain.java 、 UpdateChain.java 以及 DbChain.java 用于对数据进行链式查询操作和链式操作(修改和删除)。

例如,查询文章列表代码如下:

@SpringBootTest
classArticleServiceTest {@AutowiredArticleService articleService;@TestvoidtestChain() {List<Article> articles = articleService.queryChain().select(ARTICLE.ALL_COLUMNS).from(ARTICLE).where(ARTICLE.ID.ge(100)).list();}
}

若不是在 Service 中,我们也可以通过 QueryChain.of(mapper) 方法,自己创建一个 QueryChain 实例,代码如下:

List<Article> articles = QueryChain.of(mapper).select(ARTICLE.ALL_COLUMNS).from(ARTICLE).where(ARTICLE.ID.ge(100)).list();

数据脱敏

对真实数据进行改造并提供使用, 如身份证号、手机号、卡号、客户号等个人信息都需要进行数据脱敏``MyBatis-Flex提供了@ColumnMask() 注解,以及内置的9种脱敏规则,帮助开发者方便的进行数据脱敏。例如:

@Table("tb_account")
publicclassAccount {@Id(keyType = KeyType.Auto)private Long id;@ColumnMask(Masks.CHINESE_NAME)private String userName;
}

除此之外,MyBatis-Flex 还提供了如下的8种脱敏规则,方便开发者直接使用:

  • 手机号脱敏

  • 固定电话脱敏

  • 身份证号脱敏

  • 车牌号脱敏

  • 地址脱敏

  • 邮件脱敏

  • 密码脱敏

  • 银行卡号脱敏

当 Mybaits-Flex 内置的9种脱敏规则无法满足要求时,我们还可以自定义脱敏规则,其步骤如下:

MaskManager.registerMaskProcessor("自定义规则名称", data -> {return data;})

在某些场景下,程序希望查询得到的数据是原始数据,而非脱敏数据。比如要去查询用户的手机号,然后给用户发送短信。又或者说,我们进入编辑页面编辑用户数据, 如果编辑页面展示的是脱敏数据,然后再次点击保存,那么数据库的真实数据也会被脱敏覆盖。

因此,MaskManager 提供了 execWithoutMask、skipMask、restoreMask 三个方法来处理这种场景:

try {MaskManager.skipMask();//此处查询到的数据不会进行脱敏处理accountMapper.selectListByQuery(...);
} finally {MaskManager.restoreMask();
}

数据缓存

MyBatis-Flex 是一个 MyBatis 增强框架,所以您可以使用 MyBatis 提供的二级缓存来作为数据缓存。但是它仍然有很多的缺点,比如不适用于分布式环境,在这里推荐使用 Spring Cache 模块来处理数据缓存。

@Service
@CacheConfig(cacheNames = "account")
publicclassAccountServiceImplextendsCacheableServiceImpl<MyAccountMapper, Account> {@Override@CacheEvict(allEntries = true)publicbooleanremove(QueryWrapper query) {returnsuper.remove(query);}@Override@CacheEvict(key = "#id")publicbooleanremoveById(Serializable id) {returnsuper.removeById(id);}@Override@CacheEvict(allEntries = true)publicbooleanremoveByIds(Collection<? extends Serializable> ids) {returnsuper.removeByIds(ids);}// 根据查询条件更新时,实体类主键可能为 null。@Override@CacheEvict(allEntries = true)publicbooleanupdate(Account entity, QueryWrapper query) {returnsuper.update(entity, query);}@Override@CacheEvict(key = "#entity.id")publicbooleanupdateById(Account entity, boolean ignoreNulls) {returnsuper.updateById(entity, ignoreNulls);}@Override@CacheEvict(allEntries = true)publicbooleanupdateBatch(Collection<Account> entities, int batchSize) {returnsuper.updateBatch(entities, batchSize);}@Override@Cacheable(key = "#id")public Account getById(Serializable id) {returnsuper.getById(id);}@Override@Cacheable(key = "#root.methodName + ':' + #query.toSQL()")public Account getOne(QueryWrapper query) {returnsuper.getOne(query);}@Override@Cacheable(key = "#root.methodName + ':' + #query.toSQL()")public <R> R getOneAs(QueryWrapper query, Class<R> asType) {returnsuper.getOneAs(query, asType);}@Override@Cacheable(key = "#root.methodName + ':' + #query.toSQL()")public List<Account> list(QueryWrapper query) {returnsuper.list(query);}@Override@Cacheable(key = "#root.methodName + ':' + #query.toSQL()")public <R> List<R> listAs(QueryWrapper query, Class<R> asType) {returnsuper.listAs(query, asType);}// 无法通过注解进行缓存操作@Override@Deprecatedpublic List<Account> listByIds(Collection<? extends Serializable> ids) {returnsuper.listByIds(ids);}@Override@Cacheable(key = "#root.methodName + ':' + #query.toSQL()")publiclongcount(QueryWrapper query) {returnsuper.count(query);}@Override@Cacheable(key = "#root.methodName + ':' + #page.getPageSize() + ':' + #page.getPageNumber() + ':' + #query.toSQL()")public <R> Page<R> pageAs(Page<R> page, QueryWrapper query, Class<R> asType) {returnsuper.pageAs(page, query, asType);}}

SQL审计

Mybaits-Flex 的 SQL 审计功能,默认是关闭的,若开启审计功能,需添加如下配置。

如果你近期准备面试跳槽,建议在ddkk.com在线刷题,涵盖 一万+ 道 Java 面试题,几乎覆盖了所有主流技术面试题,还有市面上最全的技术五百套,精品系列教程,免费提供。

AuditManager.setAuditEnable(true)

MyBatis-Flex 内置了一个名为 MessageFactory 的接口,我们只需实现该接口,并为 AuditManager 配置新的 MessageFactory 即可,如下所示:

publicclassMyMessageFactoryimplementsMessageFactory {@Overridepublic AuditMessage create() {AuditMessagemessage=newAuditMessage();// 在这里// 设置 message 的基础内容,包括 platform、module、url、user、userIp、hostIp 内容// 剩下的 query、queryParams、queryCount、queryTime、elapsedTime 为 mybatis-flex 设置return message;}
}

并为 AuditManager 配置新写的 MyMessageFactory

MessageFactorycreator=newMyMessageFactory();
AuditManager.setMessageFactory(creator);

自定义 MessageReporter:

publicclassMyMessageReporterimplementsMessageReporter {@OverridepublicvoidsendMessages(List<AuditMessage> messages) {//在这里把 messages 审计日志发送到指定位置//比如 // 1、通过 http 协议发送到指定服务器// 2、通过日志工具发送到日志平台// 3、通过 Kafka 等 MQ 发送到指定平台}}

自定义 MessageCollector:

publicclassMyMessageCollectorimplementsMessageCollector {@Overridepublicvoidcollect(AuditMessage auditMessage) {System.out.println(auditMessage.getFullSql());}
}

MyBatis-Flex 内置了两个 Collector,他们分别是:

  • ScheduledMessageCollector

     定时把消息通过 MessageReporter 发送到指定位置。

  • ConsoleMessageCollector

     使用其把消息输出到控制台。

多数据源

MyBaits-Flex 内置了功能完善的多数据源支持,不需要借助第三方插件或者依赖,开箱即用, 支持包括 druid、hikaricp、dbcp2、beecp 在内的任何数据源,MyBatis-Flex 多数据源配置如下:

mybatis-flex:datasource:ds1:url: jdbc:mysql://127.0.0.1:3306/dbusername: rootpassword: 123456ds2:url: jdbc:mysql://127.0.0.1:3306/db2username: rootpassword: 123456

MyBatis-Flex 提供了 4 种方式来配置数据源:

  • 编码,使用DataSourceKey.use 方法。

  • @UseDataSource("dataSourceName")

     在 Mapper 类上,添加注解,用于指定使用哪个数据源。

  • @UseDataSource("dataSourceName")

     在 Mapper 方法上,添加注解,用于指定使用哪个数据源。

  • @Table(dataSource="dataSourceName")

     在 Entity 类上添加注解,该 Entity 的增删改查请求默认使用该数据源。

优先级:DataSourceKey.use() > @UseDataSource()在方法上 > @UseDataSource()在类上 >@Table(dataSource="...")

try{DataSourceKey.use("ds2")List<Row> rows = Db.selectAll("tb_account");System.out.println(rows);
}finally{DataSourceKey.clear();
}

整体来讲,这个框架是Mybatis的增强版,几乎集成了mybatis plus、jooq、fluent mybatis的所有优点,更多的大家可以探索一番。

http://www.dtcms.com/a/483173.html

相关文章:

  • 带权并查集
  • 建设网站多少钱 郑州浏览器什么网站都能打开的
  • 安卓13_ROM修改定制化-----常用几种去除系统签名类验证的操作步骤解析
  • 安卓导出谷歌包
  • 上海百度网络推广极限优化wordpress
  • 南京市建设监理协会网站dedecms 网站根目录
  • 创建Mybatis框架
  • 从化网站建设方案百度网站好评
  • 电商网站前台模块自己做的网站加载不出验证码
  • 数据结构 03 栈和队列
  • 微商城网站建设哪家好wordpress国内优化
  • 热释电传感器(PIR Sensor)技术深度解析:从物理原理到工程实践
  • 做餐厅网站的需求分析创造网站
  • docker项目打包演示项目(数字排序服务)
  • 诸城网站建设诸城wordpress 删除缓存
  • 自动化三维测量实现精密轴承全尺寸在线测量-中科米堆CASAIM
  • glitch做网站帝国cms做笑话网站
  • 什么网站可以做动图泰州营销型网站
  • OWL与VUE3 的高级组件通信全解析
  • 外贸人常用的网站建设免费网站制作
  • 用 Python + Vue3 打造超炫酷音乐播放器:网易云歌单爬取 + Three.js 波形可视化
  • GRS 认证:再生产品的 “绿色通行证”—— 知识深度解析
  • 常平众展做网站在新西兰做兼职的网站
  • 解决拓扑排序
  • Component template requires a root element, rather than just错误
  • 网站选择空间建筑工程类招聘网站
  • 开源的故障诊断大模型(FDLM):从多模态时序到可解释智能维护
  • 【编号219】中国钢铁工业年鉴(2000-2024)
  • 企业营销策划pptseo服务公司
  • LeetCode 算法题【中等】189. 轮转数组