有没有一种方法可以在java(spring boot)应用程序中使用largeobject流,postgresql db在单独的docker容器中运行?

li9yvcax  于 2021-07-24  发布在  Java
关注(0)|答案(0)|浏览(151)

我正在一个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
我被困在这里了。有没有人在这方面有经验或好主意?

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题