null
null

Reputation: 9144

How to optimize hibernate method call in loop?

I have a java web application built using spring+hibernate.

I have code like this:

for (Account account : accountList){

    Client client = clientService.findById(account.getFkClient());  // fkClient is foreign key to Client

    if (client != null) {
        ...
        anObject.setName(client.getName());
        anObject.setAccountNo(account.getAccountNo());  
        ...
    }
    else {
        ...
        anObject.setAccountNo(account.getAccountNo());
        ...
    }

    ...
}

accountList is a List of Account entity that retrieved from hibernate call. Inside the for loop, a Client entity is retrieved from account using hibernate call inside clientService.findById method.

These are the class involved to the call:

public class ClientService implements  IClientService {
    private IClientDAO clientDAO;

    ...

    @Override
    public Client findById(Long id) throws Exception {
        return clientDAO.findById(id);
    }
}

public class ClientDAO extends AbstractHibernateDAO<Client, Long> implements IClientDAO {

    @Override
    public Client findById(Long id) throws Exception {
        return super.findById(id);
    }
}

public class AbstractHibernateDAO<T,Y extends Serializable> extends HibernateDaoSupport {

    protected Class<T> domainClass = getDomainClass();

    private Class<T> getDomainClass() {
        if (domainClass == null) {
            ParameterizedType thisType = (ParameterizedType) getClass().getGenericSuperclass();
            domainClass = (Class<T>) thisType.getActualTypeArguments()[0];
        }
        return domainClass;
    }

    public T findById(final Y id) throws SystemException {
        return (T) this.execute(new HibernateCallback<T>() {

            @Override
            public T doInHibernate(Session session) throws HibernateException, SQLException {
                return (T) session.get(domainClass, id);
            }
        });
    }
}

Note: clientService and clientDAO are spring beans object.

My question is how to optimize the clientService.findById inside the loop with hibernate? I feel the findById call make the looping process become slower.

The accountList usually contains 7000+ records, so I need something like pre-compiled query mechanism just like PreparedStatements in jdbc. Is it possible to do this with hibernate?

Note: the code above has been simplified by removing unrelated parts, the method, variable and class name are made fictious for privacy reason. If you find a typo, please let me know in the comment section since I typed the code manually.

Upvotes: 0

Views: 4711

Answers (3)

null
null

Reputation: 9144

I found the best solution. I put the query that select columns from table Account and Client joined together into a View (VIEW_ACCOUNT_CLIENT), then I made entity class (AccountClientView) for the view and fetch it using hibernate, the result is wow, it boosts the performance drastically. Using the real code, it could takes about 15-20 minutes to finish the loop, but using View, it only takes 8-10 seconds

@Entity
@Table(name = "VIEW_ACCOUNT_CLIENT")
public class AccountClientView implements Serializable {

    ...

}

Upvotes: 1

Bal&#225;zs N&#233;meth
Bal&#225;zs N&#233;meth

Reputation: 6647

It's not clear what you want to achieve. I wouldn't do service calls in a loop. Why don't you use a NamedQuery? Retrieve all Clients attached to the given Accounts, then iterate over that list of Clients.

SELECT c from Client c JOIN c.account a WHERE a.id IN (:accounIds)

But it really depends on the business requirement! Also it's not clear to me why don't you just call:

Client client = account.getClient();

You might want to load your accountList with the clients already fetched in. Either use eager fetching, or fetch join. If the Account entity does not contain a Client, you should have a very good reason for it.

Upvotes: 0

pedjaradenkovic
pedjaradenkovic

Reputation: 241

In Hibernate/JPA you can write queries with Hibernate Query Language/ JPA query language and create NamedQueries. NamedQuery is compiled when server is started so you can consider it like some kind of prepared statement.

You can try to write HQL query which can get all entity instances with single query.

I will give you example in JPQL but you can write it with HQL as well.

@NamedQueries({
    @NamedQuery(name = "QUERY_BY_ID",
    query = "SELECT u from SomeEntity se WHERE se.id IN (:idList)"),
})
class SomeEntity {
}

class SomeEntityDao {
    public List<SomeEntity> findIdList(List<Long> idList) {
        Query query = entityManager.createNamedQuery("QUERY_BY_ID");
        query.setParameter("idList", idList);

        return query.getResultList();
    }
}

Upvotes: 1

Related Questions