简体   繁体   English

使用 Spring 数据获取数据 JPA Stream

[英]Data fetching using Spring Data JPA Stream

Below is my controller下面是我的 controller

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);
    });
    }

And here is the repository这是存储库

@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();
}

Requirement is to findAll(), pagination is giving OOM, So I thought of using Stream, but getting exception.要求是findAll(),分页给OOM,所以我想用Stream,但是得到异常。

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

2019-11-15 12:30:31.468 ERROR 7484 --- [nio-8082-exec-1] ohengine.jdbc.spi.SqlExceptionHelper: Invalid argument(s) in call: setFetchSize [ERROR] org.hibernate.engine.jdbc.spi.SqlExceptionHelper - Invalid argument(s) in call: setFetchSize 2019-11-15 12:30:31.793 ERROR 7484 --- [nio-8082-exec-1] c.seddeGlobalExceptionHandler: Unhandled Exception: org.springframework.orm.jpa.JpaSystemException: could not execute query using scroll; 2019-11-15 12:30:31.468 错误 7484 --- [nio-8082-exec-1] ohengine.jdbc.spi.SqlExceptionHelper:调用中的参数无效:setFetchSize [ERROR] org.ZCB1F0208EEBF5074C6EF1ZE9 jdbc.spi.SqlExceptionHelper - Invalid argument(s) in call: setFetchSize 2019-11-15 12:30:31.793 ERROR 7484 --- [nio-8082-exec-1] c.seddeGlobalExceptionHandler: Unhandled Exception: org.springframework. orm.jpa.JpaSystemException:无法使用滚动执行查询; nested exception is org.hibernate.exception.GenericJDBCException: could not execute query using scroll Caused by: org.hibernate.exception.GenericJDBCException: could not execute query using scroll Caused by: java.sql.SQLException: Invalid argument(s) in call: setFetchSize nested exception is org.hibernate.exception.GenericJDBCException: could not execute query using scroll Caused by: org.hibernate.exception.GenericJDBCException: could not execute query using scroll Caused by: java.sql.SQLException: Invalid argument(s) in call :setFetchSize

For having a look to your source article in Medium.查看您在 Medium 中的源文章

I think the approach given in the article is much different than your's.我认为文章中给出的方法与您的方法有很大不同。 You should at first open Stateless Session .您应该首先打开Stateless Session I don't think that using the findAll() provided in spring-data uses that as it fetch all records from db.我不认为使用 spring-data 中提供的findAll()会使用它,因为它会从数据库中获取所有记录。

Fix that would be a good start.修复这将是一个好的开始。

BUG POSSIBLE ROOT CAUSE: BUG 可能的根本原因:

I see that you are using @QueryHints your HINT_FETCH_SIZE is incorrect.我看到您正在使用@QueryHints您的HINT_FETCH_SIZE不正确。 It cannot work with Integer.MIN_VALUE as value as is equals -2^31 which is a negative value.它不能与 Integer.MIN_VALUE 一起使用,因为值等于 -2^31,这是一个负值。

Reading the error log, you need to put the streaming code in a try block ie阅读错误日志,您需要将流式代码放在 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();}

Another thing I noticed is that you don't need to put @Transactional in ProductAltRepository since you already put it in TestController.我注意到的另一件事是您不需要将 @Transactional 放入 ProductAltRepository 中,因为您已经将它放入了 TestController 中。

In order to stream the results we need to satisfy three conditions:为了stream的结果我们需要满足三个条件:

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

Forward-only seems to be set already by Spring Data so we don't have to do anything special about that. Forward-only 似乎已经由 Spring Data 设置,所以我们不必对此做任何特别的事情。 Your code sample already has @Transactional(readOnly = true) annotation in the TestController which is enough to satisfy the second criteria, so @QueryHint(name = HINT_READONLY, value = "true") is not useful.您的代码示例已经在 TestController 中有 @Transactional(readOnly = true) 注释,足以满足第二个条件,因此 @QueryHint(name = HINT_READONLY, value = "true") 没有用。 The fetch-size seems useful. fetch-size 似乎很有用。

Below is an extract from one of my projects:以下是我的一个项目的摘录:

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();
    }

Controller Controller

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";
    }
}

Let JPA Help you in pagination, why this much extra efforts?让 JPA 帮助您进行分页,为什么要付出这么多额外的努力?

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM