Reputation: 1126
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?
Upvotes: 1
Views: 6949
Reputation: 5709
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
Upvotes: 2