将大文件上传和下载到 PostgreSQL 而不消耗大量 RAM
Posted
技术标签:
【中文标题】将大文件上传和下载到 PostgreSQL 而不消耗大量 RAM【英文标题】:Upload and download big files into PostgreSQL without consuming a lot RAM 【发布时间】:2018-03-26 10:02:05 【问题描述】:我设法使用此 Java 代码成功上传和下载文件:
上传
ps = conn.prepareStatement("INSERT INTO DOCUMENT_TEMPLATE_FILES (ID, DOCUMENT_TEMPLATE_ID, FILE_NAME, FILE) "
+ " VALUES (?, ?, ?, ?)");
ps.setInt(1, obj.number);
ps.setInt(2, obj.number);
ps.setString(3, file.getSubmittedFileName());
InputStream inputStream = file.getInputStream();
ps.setBinaryStream(4, inputStream, inputStream.available());
ps.executeUpdate();
下载
ps = conn.prepareStatement("SELECT *, OCTET_LENGTH(FILE) AS FILE_LENGTH FROM DOCUMENT_TEMPLATE_FILES WHERE DOCUMENT_TEMPLATE_ID = ?");
ps.setInt(1, id);
ResultSet rs = ps.executeQuery();
while (rs.next())
String file_name = rs.getString("FILE_NAME");
.........
byte[] buffer = new byte[4096];
try (InputStream input = rs.getBinaryStream("FILE");
OutputStream output = response.getOutputStream())
int numRead = 0;
while ((numRead = input.read(buffer)) != -1)
output.write(buffer, 0, numRead);
但是当我尝试将它用于 2GB 文件时,我得到了内存大小的异常。不幸的是,文件在插入/选择期间存储在 RAM 中。
是否有另一种方法可以在不消耗太多 RAM 内存的情况下解决此问题?
【问题讨论】:
file
列的数据类型是什么?
@a_horse_with_no_name 目前是 BYTEA,但如果您推荐,我可以更改它。
bytea
列的最大长度为 1GB
@a_horse_with_no_name 好的,您可以推荐哪种列类型来解决上述问题?
您必须使用large objects,但使用起来相当复杂:jdbc.postgresql.org/documentation/head/binary-data.html
【参考方案1】:
为什么不使用本地文件系统来存储可以流式传输的文件,而只使用数据库中的文件信息?数据库中的 2GB 文件是一个坏主意,那么您试图通过膨胀表空间来实现什么?只需选择文件名并启动 Streamreader/Streamwriter。
【讨论】:
这将需要 Java 程序在数据库服务器上运行——这通常不是这种情况 是的,关于数据库服务器上的 Java 程序,您是对的。但这就是发明cdn服务器的原因,只需返回链接并将http 301返回到cdn链接。只是一个想法,将这么大的 blob 存储到数据库是不常见的,单独备份它有时会很糟糕。以上是关于将大文件上传和下载到 PostgreSQL 而不消耗大量 RAM的主要内容,如果未能解决你的问题,请参考以下文章
将大文件上传到 Apache FileUpload 时忽略 Servlet 响应