V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ASpiral
V2EX  ›  Java

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

  •  
  •   ASpiral · 2019-05-09 11:09:37 +08:00 · 3111 次点击
    这是一个创建于 2025 天前的主题,其中的信息可能已经有所发展或是发生改变。

    想把前端通过网页上传的文件写入 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,这么大的文件一般是怎么读写的啊?有没有办法像流那样从开始接收文件时就写入数据库,边读边写,并且可以事务控制?
    求大佬给点思路或者有没有现成的轮子可以用…

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