mybatis 处理 lob 字段应避免默认全量加载导致 oom,须用 jdbc 流式读写:查询时字段声明为 java.sql.clob/blob 并配置对应 jdbctype,业务层调用 getcharacterstream()/getbinarystream();插入时禁用 #{xxx},改用原生 preparedstatement 的 setclob/setblob 方法流式设值。

MyBatis 处理 LOB(CLOB/BLOB)字段,关键不是“能不能存”,而是“怎么避免 OOM 和性能陷阱”。默认映射会把整个大字段一次性加载进内存,50MB 的 PDF 或日志文本就可能让应用直接崩溃。真正安全的做法是绕过自动类型转换,用 JDBC 原生流式能力控制读写节奏。
查询:返回 Clob/Blob 对象,别转 String 或 byte[]
MyBatis 默认的 ClobTypeHandler 会调用 clob.getSubString(1, (int) clob.length()),ByteArrayTypeHandler 同样全量加载 blob.getBytes()——这是 OOM 的主因。
- 实体类字段声明为
java.sql.Clob或java.sql.Blob(不是String或byte[]) - Mapper XML 中显式配置:
<result column="content" property="clobContent" jdbctype="CLOB" javatype="java.sql.Clob"></result> - 业务层拿到对象后,按需流式读取:
• CLOB →clob.getCharacterStream()(配IOUtils.copy()或逐行解析)
• BLOB →blob.getBinaryStream()(适合写文件、上传、分块处理)
插入:用 PreparedStatement 流式设值,别塞 #{xxx}
不要在 SQL 中用 #{memo} 直接传大内容,MyBatis 无法对大参数做流式处理,会先转成字符串或字节数组再绑定。
- 推荐在 Service 层获取原生连接:
sqlSession.getConnection(),然后创建PreparedStatement - 调用 JDBC 原生方法:
•ps.setClob(2, new FileReader("file.txt"))
•ps.setBlob(3, new FileInputStream("photo.jpg"))
• 支持指定长度重载(如setClob(int, Reader, long)),更可控 - 若必须用 MyBatis XML 插入,需自定义
TypeHandler实现流式写入,但复杂度高、维护成本大,不建议初用
数据库与类型映射要对齐
不同数据库对 LOB 的 JDBC 类型名略有差异,但 MyBatis 的 jdbcType 是标准化的:
- MySQL:
TEXT/LONGTEXT→jdbcType="CLOB";BLOB/LONGBLOB→jdbcType="BLOB" - Oracle/PostgreSQL:直接对应
CLOB/BLOB类型,映射一致 - 建表时注意容量匹配:MySQL 中
LONGTEXT最大 4GB,LONGBLOB同样支持 4GB,但实际使用建议单条不超过 100MB,并配合超时与连接池调优
什么时候才需要转成 String 或 byte[]?
仅当业务强依赖全文检索、前端直出 HTML、或简单校验前 N 字符时才考虑转换,且必须加长度防护:
if (clob.length() > 10 * 1024 * 1024) throw new IllegalArgumentException("CLOB too large for string conversion");if (blob.length() > 5 * 1024 * 1024) throw new IllegalArgumentException("BLOB too large for byte[] conversion");- 转换后立即释放引用,避免长生命周期持有大对象











