如何在循环中优化hibernate方法调用?

时间:2013-03-27 11:09:42

标签: java spring hibernate optimization jpa

我有一个使用spring + hibernate构建的java Web应用程序。

我有这样的代码:

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是从hibernate调用中检索的Account实体列表。在for循环中,使用 clientService.findById 方法中的hibernate调用从帐户中检索客户端实体。

这些是参与电话会议的课程:

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

注意:clientService和clientDAO是spring beans对象。

我的问题是如何使用hibernate优化循环内的clientService.findById?我觉得findById调用使循环过程变慢。

accountList通常包含7000多条记录,所以我需要类似预编译查询机制的东西,就像jdbc中的PreparedStatements一样。可以用hibernate做到这一点吗?

注意:通过删除不相关的部分简化了上面的代码,方法,变量和类名因隐私原因而变得虚假。如果您发现拼写错误,请在评论部分告诉我,因为我手动输入了代码。

3 个答案:

答案 0 :(得分:1)

在Hibernate / JPA中,您可以使用Hibernate查询语言/ JPA查询语言编写查询并创建NamedQueries。在启动服务器时编译NamedQuery,因此您可以将其视为某种预准备语句。

您可以尝试编写HQL查询,该查询可以通过单个查询获取所有实体实例。

我会在JPQL中给你一些例子,但你也可以用HQL编写它。

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

答案 1 :(得分:1)

我找到了最好的解决方案。我将查询表从Account和Client连接在一起的视图(VIEW_ACCOUNT_CLIENT),然后我为视图创建实体类(AccountClientView)并使用hibernate获取它,结果是哇,它大大提升了性能。使用真实代码,完成循环可能需要大约15-20分钟,但使用View,只需要8-10秒

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

    ...

}

答案 2 :(得分:0)

目前尚不清楚您想要实现的目标。我不会在循环中进行服务调用。你为什么不使用NamedQuery? 检索附加到给定Clients的所有Accounts,然后迭代Clients列表。

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

但这实际上取决于业务需求! 另外我不清楚为什么你不打电话:

Client client = account.getClient();

您可能希望使用已提取的客户端加载accountList。使用预先提取或fetch join。如果Account实体不包含Client,那么您应该有充分的理由。