我正在一个docker容器中运行一个带有SpringBoot后端和react.js前端的应用程序,该容器访问第二个容器中提供的postgresql数据库。通过hibernate的常见sql语句工作得很好,我可以访问数据库中的所有表。现在的用例是从数据库中读取blob(约400mb的文件),并将它们直接流式传输到客户端的http响应中,以避免将所有内容加载到ram中。
我的spring控制器中的数据访问方法如下所示:
@Transactional
@GetMapping("/downloadFile/{fileId}")
public StreamingResponseBody downloadFile(@PathVariable long fileId, HttpServletResponse response)
throws Exception {
// Load file meta data from database
List<Object[]> entryList = repository.findMetaById(fileId);
if(entryList.isEmpty()) {
throw new RuntimeException("File with id " + fileId + " not found.");
}
Object[] found = entryList.get(0);
response.addHeader("Content-disposition", "attachment;filename=" + found[1]);
response.setContentType(found[2].toString());
return new StreamingResponseBody() {
@Override
public void writeTo(OutputStream out) throws IOException {
streamContentFromDB(fileId, out);
}
};
}
private void streamContentFromDB(final long id, final OutputStream streamToWrite) {
try {
entityManager = entityManager.getEntityManagerFactory().createEntityManager();
Session session = entityManager.unwrap(Session.class);
session.doWork(new Work() {
@Override
public void execute(Connection connection) throws SQLException {
connection.setAutoCommit(false);
PGConnection pgCon = connection.unwrap(PGConnection.class);
LargeObjectManager lobj = pgCon.getLargeObjectAPI();
PreparedStatement stmt = connection
.prepareStatement("Select d.customerdata from FSH_DOWNLOAD_DATA d where d.id=?");
stmt.setLong(1, id);
ResultSet rs = stmt.executeQuery();
rs.next();
if (rs != null) {
long oid = rs.getLong(1);
// set buffer size to 5 MB
int bufferSize = 5 * 1024;
LargeObject obj = lobj.open(oid, LargeObjectManager.READ);
int totalSize = obj.size();
byte buffer[] = new byte[totalSize > bufferSize ? bufferSize : totalSize];
InputStream input = obj.getInputStream();
int count;
int remainingSize = totalSize;
try {
while ((count = input.read(buffer)) > 0) {
streamToWrite.write(buffer);
remainingSize -= count;
buffer = new byte[remainingSize > bufferSize ? bufferSize : remainingSize];
}
input.close();
obj.close();
} catch (IOException e) {
logger.error("Error writing to output stream: ", e);
}
rs.close();
}
stmt.close();
}
});
} catch (Exception e) {
logger.error("Error loading the file with id " + id + ": ", e);
}
}
我观察到的问题是,物体 LargeObject obj = lobj.open(oid, LargeObjectManager.READ);
不知何故是空的,并且没有可用的数据或流。但是,它包含数据库条目的正确oid!
此外,如果postgres直接安装在主机上,而不是安装在容器中,那么这种设置工作得非常好。
spring-boot版本v2.3.4.release,postgres托管依赖42.2.16;postgres docker图像postgres:13.1
我被困在这里了。有没有人在这方面有经验或好主意?
暂无答案!
目前还没有任何答案,快来回答吧!