简体   繁体   English

在 Spring 中使用 JPA 规范获取要执行的查询

[英]Get the query to be executed using JPA Specifications in Spring

I've a spring project where I need to export a query resultset into excel sheet.我有一个 spring 项目,我需要将查询结果集导出到 Excel 表中。 Currently I'm using JPA repository to get the data from the DB and i'm using Apache POI libraries to prepare excel sheet from this data.目前我正在使用JPA repository从数据库中获取数据,并且我正在使用Apache POI库从这些数据中准备 excel 表。

// Get data from DB using jpaRepository
Page<MyPOJO> data = myPOJOJpaRepository.findAll(specifications, pageRequest);

// Prepare Excel Sheet from the data object using POI libraries

Now, the problem is getting the data in the form of Java POJOs is taking too much time (almost 60 secs) and preparing excel sheet using the POI libraries is also taking almost 60 secs.现在,问题是获取 Java POJO 形式的数据花费了太多时间(将近 60 秒),并且使用 POI 库准备 excel 表也花费了近 60 秒。

When I tried to export a csv file instead using the resultset (instead of java POJOs), it is finishing in under 10 secs.当我尝试使用结果集(而不是 java POJO)导出 csv 文件时,它在 10 秒内完成。

 ResultSet resultSet = statement.executeQuery("select * from table where some_filters");
 File file = writeResultsToCSVFile(resultSet);

I'm using JPA specifications to build the query in the current architecture.我正在使用JPA specifications在当前架构中构建查询。 Is there anyway to get the query that is going to execute so that I can directly get the resultset (instead of POJOs) and prepare the csv file instead.无论如何要获取将要执行的查询,以便我可以直接获取结果集(而不是 POJO)并准备 csv 文件。

// I'm looking for something like follows:
ResultSet resultSet = statement.executeQuery(specifications.getQuery());
File file = writeResultsToCSVFile(resultSet);

Is there anyway to achieve something like this?有没有办法实现这样的目标?

It's a bit tricky because you can obtain a non-standard query like this:这有点棘手,因为您可以获得这样的非标准查询:

select generatedAlias0 from Pets as generatedAlias0 where generatedAlias0.pet_name=:param0

You have to obtain the query, then you need to manipulate something like requested fields and bound params (managing their types. note that in this example I managed only string type).您必须获得查询,然后您需要操作诸如请求字段和绑定参数之类的东西(管理它们的类型。请注意,在此示例中我只管理了字符串类型)。

So assuming you are using Hibernate you can do something like this:因此,假设您正在使用 Hibernate,您可以执行以下操作:

/**
 *
 */
public static Specification<Pets> findByCriteria() {

    return new Specification<Pets>() {

        @Override
        public Predicate toPredicate(Root<Pets> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

            List<Predicate> predicates = new ArrayList<Predicate>();

            // solo attivita attive
            predicates.add(cb.equal(root.get("pet_name"), "Chelsea"));

            return cb.and(predicates.toArray(new Predicate[]{}));
        }
    };
}

/**
 * TODO MANAGE VARIOUS TYPES
 */
private String createParam(Parameter<?> p, Query<?> q) {

    Class<?> clz = p.getParameterType();
    if (clz == String.class) {
        return "'" + q.getParameterValue(p.getName()) + "'";
    }
    return "";
}


/**
 *
 */
public void getEnterprisesAdmin() {

    Specification<Pets> spec = this.findByCriteria();

    CriteriaBuilder builder = this.em.getCriteriaBuilder();
    CriteriaQuery<Pets> query = builder.createQuery(Pets.class);

    Root<Pets> root = query.from(Pets.class);

    Predicate predicate = spec.toPredicate(root, query, builder);
    query.where(predicate);

    TypedQuery<Pets> findAllBooks = em.createQuery(query);
    Query<Pets> q = findAllBooks.unwrap(Query.class);

    String strQuery = q.getQueryString();

    strQuery = Pattern.compile("(.*?)select \\w*").matcher(strQuery).replaceFirst("SELECT *");

    Set<Parameter<?>> pList = q.getParameters();
    Iterator<Parameter<?>> iter = pList.iterator();
    for (int i=0; i<pList.size(); i++) {
        Parameter<?> p = iter.next();
        strQuery = strQuery.replace(":" + p.getName(), this.createParam(p, q));
    }

    try {
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mempoi?useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC", "root", "");
        Statement stmt = conn.createStatement();
        ResultSet resultSet = stmt.executeQuery(strQuery);

        resultSet.next();
        System.out.println("PET NAME: " + resultSet.getString("pet_name"));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

You have given me a good idea for the next feature to implement in my lib MemPOI (designed for managing cases like yours) that supplies an abstraction layer for Apache POI.您给了我一个好主意,让我在我的库MemPOI (设计用于管理像您这样的案例)中实现下一个功能,该功能为 Apache POI 提供抽象层。 I'll implement the export directly from a Specification我将直接从Specification实现导出

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

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