简体   繁体   中英

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. 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.

// 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.

When I tried to export a csv file instead using the resultset (instead of java POJOs), it is finishing in under 10 secs.

 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. 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.

// 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:

/**
 *
 */
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. I'll implement the export directly from a Specification

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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