MyBatis的隐形炸弹:selectByExampleWithBLOBs使用不当,让性能下降80%

关注我的公众号:【编程朝花夕拾】,可获取首发内容。

01 引言

在MyBatis项目开发中,你是否遇到过查询突然变慢、内存占用飙升的困扰?这很可能是selectByExampleWithBLOBs使用不当导致的性能陷阱。

本文将为你揭秘这个看似简单却暗藏玄机的方法,从使用场景到性能优化,助你掌握BLOB字段查询的精髓,避免常见坑点。

02 缘起

这两天遇到一个线上BUG,就是因为selectByExampleWithBLOBs问题导致的。如图所示:

从报错的日志信息来看,是因为selectByExampleWithBLOBs没有绑定Mapper.xml文件。

问题很快就排查了,因为新加了字段需要使用逆向工程(MBG)重新生成实体。而生成的实体的时候,开发者对Text类型的字段直接指定了类型,导致BLOB字段丢失,Mapper.xml也不会有xxxxWithBLOBs的方法,导致问题产生。

默认的映射是将Text字段单独拿出来,使用xxxWithBLOBs单独接收,对应的xml也会生成类似selectByExampleWithBLOBs的方法,如图:

接下我们将一起探索xxxWithBlobs的用法。

03 概述

selectByExampleWithBLOBsMyBatis GeneratorMBG)自动生成代码时针对包含BLOBBinary Large Object)字段的表的查询方法。它允许通过Example条件对象进行查询,同时包含对BLOB字段的检索。

当数据库表中包含BLOB、CLOB、TEXT等大字段类型时,MBG会生成两个查询方法:

  • selectByExample:查询时不包含BLOB字段
  • selectByExampleWithBLOBs:查询时包含BLOB字段

04 代码示例

4.1 数据库表结构

sql 复制代码
CREATE TABLE `article` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(200) NOT NULL,
  `author` varchar(100) DEFAULT NULL,
  `content` longtext, -- BLOB类型字段
  `summary` text, -- BLOB类型字段
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

4.2 自动生成实体以及配置

MyBatis Generator自动生成代码工具这里就详细说明了,直接使用工具生成。

我们可以看到ArticleWithBLOBs继承BaseArticle数据库实体类,contentsummary已经单独处理了。

xml配置文件也有类似的方法:

4.3 使用

xxxWithBLOBs的使用很简单,就和selectByExample几乎一样。

java 复制代码
// 创建Example对象
ArticleExample example = new ArticleExample();
ArticleExample.Criteria criteria = example.createCriteria();

// 设置查询条件
criteria.andAuthorEqualTo("张三")
        .andCreateTimeGreaterThan(DateUtils.addDays(new Date(), -7));

// 排序
example.setOrderByClause("create_time DESC");

// 1. 普通查询(不获取content字段)
List<Article> articles1 = articleMapper.selectByExample(example);

// 2. 包含BLOB字段的查询
List<ArticleWithBLOBs> articles2 = articleMapper.selectByExampleWithBLOBs(example);
// 此时articles2中的每个Article对象都包含content字段的数据

selectByExampleselectByExampleWithBLOBs的返回值不一样哦。

05 注意事项

5.1 性能问题

MBG为什么要把Text类型的字段单独处理呢?会有什么性能问题么?

Text字段通常存储大量数据,如文章内容、协议内容等,大数据量传递会消耗带宽以及IO等,从而影响性能。

所以,查询时不需要Text类型的字段时,尽量不要查询。遵循需要什么查什么的最少资源的模式,可以提高接口性能。

java 复制代码
// 不推荐:不必要的BLOB查询
ArticleExample example = new ArticleExample();
example.createCriteria().andStatusEqualTo(1);
// 如果只需要统计数量或非BLOB字段,应使用普通查询
List<Article> articles = articleMapper.selectByExample(example); // 更好

// 需要BLOB数据时才使用WithBLOBs
List<ArticleWithBLOBs> articlesWithBlobs = articleMapper.selectByExampleWithBLOBs(example);

5.2 字段排除与包含

MBG配置中可以控制BLOB字段的生成策略:

xml 复制代码
<table tableName="article" domainObjectName="Article">
    <property name="useActualColumnNames" value="false" />
    <property name="domainPackage" value="base" />
    <columnRenamingRule searchString="is_" replaceString="" />

    <!-- 默认映射 -->
    <columnOverride column="content" javaType="String" jdbcType="LONGVARCHAR"/>
</table>

columnOverride用来指定生成的字段类型,上述代码为默认映射,可以通过指定jdbcType或者javaType来干涉生成的字段。

5.3 ResultMap差异

MBG会生成两个ResultMap:

  • BaseResultMap:不包含BLOB字段
  • ResultMapWithBLOBs:包含BLOB字段

5.4 Mapper兼容

selectByExampleWithBLOBsMGB默认方法,生成的xxxMapper可能会不包此方法,这个和MGB这个工具有关系。我的工具里面就没有。

需要手动处理。

06 小结

小编觉得selectByExampleWithBLOBs应该做到非必要不使用,减少资源的消耗。如果存储的数据没有非常大的时候,应该避免使用text等大数据类型的。合理使用才是性能优化的关键,让大数据字段不再成为系统负担。

相关推荐
刘一说9 小时前
Java 中实现多租户架构:数据隔离策略与实践指南
java·oracle·架构
千寻girling9 小时前
《 MongoDB 教程 》—— 不可多得的 MongoDB
前端·后端·面试
Wiittch9 小时前
HashMap源码深度剖析
后端
若水不如远方9 小时前
分布式一致性(三):共识的黎明——Quorum 机制与 Basic Paxos
分布式·后端·算法
三千星9 小时前
从Java到AI:我的转型之路 Ⅱ —— 手撸一个DeepSeek工具库
后端
beata9 小时前
Java基础-9:深入 Java 虚拟机(JVM):从底层源码到核心原理的全面解析
java·后端
SimonKing9 小时前
分享一款可以管理本地端口的IDEA插件:Port Manager
java·后端·程序员
索荣荣9 小时前
Maven配置文件(pom.xml)终极指南
java·开发语言
代码栈上的思考9 小时前
SpringBoot 拦截器
java·spring boot·spring
送秋三十五9 小时前
一次大文件处理性能优化实录————Java 优化过程
java·开发语言·性能优化