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等大数据类型的。合理使用才是性能优化的关键,让大数据字段不再成为系统负担。

相关推荐
葫芦和十三15 小时前
图解 MongoDB 21|选举与 failover:Primary 是怎么选出来的
后端·mongodb·agent
GetcharZp15 小时前
26k Star 开源内网穿透神器 NetBird,一分钟实现全球设备互联!
后端
考虑考虑16 小时前
Mybatis实现批量插入
java·后端·mybatis
咖啡八杯17 小时前
GoF设计模式——中介者模式
java·后端·spring·设计模式
lizhongxuan19 小时前
多Agent之间的区别
后端
青石路21 小时前
记一次多JDK版本问题的排查,一坑套一坑,差点没爬上来
java
杨充21 小时前
1.面向对象设计思想
后端
IT_陈寒21 小时前
Java的Date类又坑了我一次,改用时间戳真香
前端·人工智能·后端
systemPro1 天前
2.6亿条设备数据,历史查询从超时到50ms,我做了什么
后端
要阿尔卑斯吗1 天前
提示词优化启示:为什么“按顺序输出“比“关键度评分“更有效
后端