求助:大文件写入数据库报错 OutOfMemoryError: Java heap space

2019-05-09 11:09:37 +08:00
 ASpiral

想把前端通过网页上传的文件写入 mysql,后台用的公司的框架(基于 spring+mybatis),数据库表字段类型用 longblob,实体类字段类型用 byte[];
文件较小的时候读写都没问题,但文件稍微大点写入就报错,试了下大概大于 128M 就不行了

java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:3332)
    at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)
    at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:448)
    at java.lang.StringBuilder.append(StringBuilder.java:136)
    ...(从这里开始的报错来自框架)

通过本地调试,发现后台在接收完文件准备写入数据库阶段报错,在这阶段任务管理器的"java.exe"进程从 1000MB+飙到 2000MB+,试着添加 JVM 参数-Xmx2048m 还是不行…
我才写入一个 100M+的文件怎么内存就占这么多了… mysql 的 longblob 可以存 4G,这么大的文件一般是怎么读写的啊?有没有办法像流那样从开始接收文件时就写入数据库,边读边写,并且可以事务控制?
求大佬给点思路或者有没有现成的轮子可以用…

3111 次点击
所在节点    Java
16 条回复
kaneg
2019-05-09 11:20:56 +08:00
你估计把整个文件读到内存了,内存在对象传递过程中可能还要复制来复制去,所以最终比文件大。你要做的就是用分段或者流式写入数据库。
wc951
2019-05-09 12:18:42 +08:00
byte[]改成 blob 用流
wc951
2019-05-09 12:21:34 +08:00
更好的办法是数据库存文件路径,文件单独存储,不管是磁盘存储还是 dfs 都可以
gz911122
2019-05-09 12:25:31 +08:00
文件请存 oss,
数据库保留路径就可以了
momocraft
2019-05-09 12:27:31 +08:00
jdbc 可以绑 InputStream 为 SQL 参数
fhsan
2019-05-09 12:39:09 +08:00
文件肯定存到本地、HDFS、云硬盘之类的,怎么会有写入数据库这种操作?我以前的公司有人就喜欢存 JSON 到数据库,每次查询都卡爆。
opengps
2019-05-09 13:04:05 +08:00
文件为啥要写入数据库?
ASpiral
2019-05-09 13:54:30 +08:00
@kaneg @wc951 @momocraft
用流不知道怎么操作…实体类字段用 Blob 类型在写入数据库时值变成 null 了,难道得手动获取 PreparedStatement 手写 sql 语句再 setBlob 吗?这样就用不了框架自带的事务控制了…
@gz911122 @fhsan @opengps
需求就是这样…数据库都有 blob 类型字段为什么不给写入数据库啊?
gz911122
2019-05-09 14:13:15 +08:00
@ASpiral
1 blob 不是用来存文件的
2 减轻数据库压力
3 减轻带宽压力
4 提高速度
opengps
2019-05-09 14:25:45 +08:00
@ASpiral 文件写入数据库虽然不排斥,但是也不提倡。
大文件读写很占用的连接比较久,而且文件类往往可能有静态加速等方式,行锁需要担心的问题,在大文件写入时候会暴露的更加明显等
des
2019-05-09 14:30:04 +08:00
数据库写文件还是不要了吧,更何况还是这么大的文件
micean
2019-05-09 14:30:22 +08:00
#5 +1
youxiachai
2019-05-09 14:31:19 +08:00
想起我刚入行的时候......
就有人跟我说,数据库的二进制不是用来纯文件的....
fhsan
2019-05-09 15:08:34 +08:00
数据库变的巨大,数据库字段的 IO 远远的低于文件系统的 IO,越来越耗时间
文件的备份、还原、查找、内容检索等等,也成了一大问题
如果文件频繁读写增删改查数据,你的数据库立马就崩掉,即使不崩也无法处理大的负载
数据库锁的问题,如果一个人修改字段会阻塞其他读的,直接 500 超时
ASpiral
2019-05-09 18:06:53 +08:00
@all 感谢各位的建议!
跟领导反馈了,领导的意见是先实现了再说,毕竟这是客户需求
以后应该是另建一个数据库放文件存储的表,单独一台服务器,后台跟数据库服务器都在内网
领导建议我文件分块写入数据库,存做多条记录,我该研究怎么分块写入跟取出了…
sonyxperia
2019-05-10 16:41:08 +08:00
百兆的文件写入数据库= =
客户的要求也不能都答应啊

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/562447

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX