使用Spring Data JPA Stream获取数据



下面是我的控制器

public class TestController {
@PersistenceContext
EntityManager entityManager;
@Autowired
ProductAltRepository productAltRepository;
@GetMapping("/findAll")
@Transactional(readOnly = true)
public void findAll() {
Stream<ProductAltRelEntity> productAltRelEntities = productAltRepository.findAllProductAlts();
List<ProductAltRelEntity> productAlts = Lists.newArrayList();
productAltRelEntities.forEach(x -> {
productAlts.add(x);
entityManager.detach(x);
});
}

这是存储库

@Repository
@Transactional
public interface ProductAltRepository
extends JpaRepository<ProductAltRelEntity, Long>, JpaSpecificationExecutor<ProductAltRelEntity>{
@QueryHints(value = { @QueryHint(name = HINT_FETCH_SIZE, value = "" + Integer.MIN_VALUE),
@QueryHint(name = HINT_CACHEABLE, value = "false"), @QueryHint(name = HINT_READONLY, value = "true"), })
@Query("SELECT p FROM ProductAltRelEntity p")
public Stream<ProductAltRelEntity> findAllProductAlts();
}

要求是findAll((,分页是OOM,所以我想到了使用Stream,但得到了异常。

[WARN] org.hibernate.engine.jdbc.spi.SqlExceptionHelper - SQL Error: 17068, SQLState: 99999

2019-11-15 12:30:31.468错误7484-[nio-8082-exec-1]o.h.engine.jdbc.spi.SqlExceptionHelper:调用中的参数无效:setFetchSize[错误]org.hubinate.engine.jdbc.spi.SqlExceptionHelper-调用中的参数无效:setFetchSize2019-11-15 12:30:31.793错误7484-[nio-8082-exec-1]c.s.e.d.d.e.GlobalExceptionHandler:未处理的异常:org.springframework.org.jpa.JpaSystemException:无法使用滚动执行查询;嵌套异常为org.hubinate.exception.GenericJDBCException:无法使用滚动执行查询导致原因:org.hubinate.exception.GenericJDBCException:无法使用滚动执行查询由以下原因引起:java.sql.SQLException:调用中的参数无效:setFetchSize

读取错误日志时,需要将流代码放入try块中,即

try(Stream<ProductAltRelEntity> productAltRelEntities = productAltRepository.findAllProductAlts()){
List<ProductAltRelEntity> productAlts = Lists.newArrayList();
productAltRelEntities.forEach(x -> {
productAlts.add(x);
entityManager.detach(x);
});
} catch(Exception ex) {ex.printStackTrace();}

我注意到的另一件事是,你不需要把@Transactional放在ProductAltRepository中,因为你已经把它放在TestController中了。

为了流式传输结果,我们需要满足三个条件:

Forward-only resultset
Read-only statement
Fetch-size set to Integer.MIN_VALUE

前进似乎只是由Spring Data设置的,所以我们不必对此做任何特别的事情。您的代码示例在TestController中已经有@Transactional(readOnly=true(注释,这足以满足第二个条件,所以@QueryHint(name=HINT_readOnly,value="true"(没有用处。提取大小似乎很有用。

以下是我的一个项目的摘录:

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import static org.hibernate.jpa.QueryHints.HINT_FETCH_SIZE;
public interface IssueRepo extends JpaRepository<Issue, Long>, JpaSpecificationExecutor<Issue> {    

@QueryHints(value = @QueryHint(name = HINT_FETCH_SIZE, value = "" + Integer.MIN_VALUE))
@Query("select t from Issue t ")
Stream<Issue> getAll();
}

控制器

public class ManageIssue {
@GetMapping("all/issues")
@Transactional(readOnly = true)
public String getAll() {
System.out.println("Processing Streams ...");
try(Stream<Issue> issuesList = issueRepo.getAll()){

issuesList.forEach(issue -> {
System.out.println(issue.getId()+" Issue "+issue.getTitle());
});
} catch(Exception ex) {ex.printStackTrace();}
return "All";
}
}

查看Medium中的源文章。

我认为文章中给出的方法与你的大不相同。您应该首先打开无状态会话。我不认为使用spring数据中提供的findAll()会在从db获取所有记录时使用它。

修复这将是一个良好的开端。

气泡可能的根本原因:

我看到您正在使用@QueryHints,您的HINT_FETCH_SIZE不正确。它不能与Integer.MIN_VALUE一起工作,因为它的值等于-2^31,这是一个负值。

让JPA帮助您进行分页,为什么要付出这么多额外的努力?

Page<ProductAltRelEntity> productAltRelEntity= productAltRepository
.findAll(PageRequest.of(page - 1, 10, Sort.by("createdon").descending()));

最新更新