【发布时间】:2018-04-19 12:43:26
【问题描述】:
最近几天我在互联网上上下搜索,并尝试了所有我能想到的。我认为自己现在别无选择。
在 java 8 spring boot rest 应用程序中,我有一个
JPA 存储库:
@Transactional
public interface PageRepository extends JpaRepository<ListPage, Long> {
static final String CLAUSE_AND_PAGE_NR = " and lp.pageNumber = :pageNumber";
static final String BY_LIST_ID = "from ListPage lp inner join lp.listInstance li where li.objectId = :listId";
static final String FIND_CONTENT = "select lp.content ";
@Query(value = FIND_CONTENT + BY_LIST_ID + CLAUSE_AND_PAGE_NR)
public String findContentByListIdAndPageNumber(@Param("listId") final Long listId, @Param("pageNumber") final Integer pageNumber);
}
控制器:
@RestController
@RequestMapping("/download")
public class DownloadController {
private final Logger logger = LoggerFactory.getLogger(DownloadController.class);
@Resource
ListRepository listRepository;
@Resource
PageRepository pageRepository;
@RequestMapping(value = "/list/{id}/browse-txt", method = RequestMethod.GET, produces= MediaType.TEXT_PLAIN_VALUE)
public ResponseEntity<StreamingResponseBody> getListAsSingleFileBrowseTxt(@PathVariable(value="id") Long listId,
HttpServletResponse response,
HttpServletRequest request) {
ListInstance list = listRepository.findOne(listId);
response.setHeader("Content-Disposition", "inline; filename=" + renameFileExtension(list.getFileName(),".TXT"));
response.setHeader("content-type", "text/plain");
return getResponse(auth.getCorporateKey(), list);
}
private ResponseEntity<StreamingResponseBody> getResponse (String corporateKey, ListInstance list) {
Long listId = list.getObjectId();
StreamingResponseBody responseBody = out -> {
Integer pageCount = pageRepository.countByListId(listId);
long bytesBuffered = 0;
ByteArrayOutputStream buff = new ByteArrayOutputStream();
String pageString;
byte[] pageBytes;
for (Integer i = 1; i <= pageCount; i++) {
try {
pageString = pageRepository.findContentByListIdAndPageNumber(listId, i);
buff.write(pageBytes);
bytesBuffered += buff.size();
if (bytesBuffered > 1024) { //flush after 1KB
bytesBuffered = 0;
out.write(buff.toByteArray());
out.flush();
buff.reset();
}
}
catch (Exception e) {
logger.error("error writing lazy buffer: page " + i + " of list " + listId, e);
}
}
out.write(buff.toByteArray());
out.flush();
};
return new ResponseEntity(responseBody, HttpStatus.OK);
}
}
当我调用控制器时,一切都按预期工作。我在浏览器中看到页面以 1k 的形式出现。这就是我想要的,大型内容的懒加载。
但突然之间(并不总是在同一页面上)它崩溃了: org.springframework.transaction.CannotCreateTransactionException:无法为事务打开 JPA EntityManager;嵌套异常是 java.lang.IllegalStateException: EntityManager is closed
我知道,这是因为 JPA 存储库在不同的线程中运行,在该线程中创建存储库的线程已经完成(我在单个线程中尝试了读取循环并且有效)。
我的问题是: 如何防止 JPA 连接(我应该怎么称呼它)在不同的线程中消失?
有人请给我另一个提示。
问候
S.
【问题讨论】:
标签: java spring multithreading hibernate jpa