Java 如何优化hibernate方法在循环中的调用?
我有一个使用spring+hibernate构建的java web应用程序 我有这样的代码:Java 如何优化hibernate方法在循环中的调用?,java,spring,hibernate,optimization,jpa,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.setN
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调用中检索到的帐户实体的列表。在for循环中,使用hibernate调用InsideclientService.findById方法从帐户中检索客户机实体
这些是调用所涉及的类:
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);
}
});
}
}
public类ClientService实现IClientService{
私人IClientDAO客户端;
...
@凌驾
公共客户端findById(长id)引发异常{
返回clientDAO.findById(id);
}
}
公共类ClientDAO扩展了抽象HibernateDAO实现了IClientDAO{
@凌驾
公共客户端findById(长id)引发异常{
返回super.findById(id);
}
}
公共类AbstractHibernateDAO扩展了HibernateDaoSupport{
受保护类domainClass=getDomainClass();
私有类getDomainClass(){
if(domainClass==null){
ParameteredType thisType=(ParameteredType)getClass().getGenericSuperclass();
domainClass=(类)thisType.getActualTypeArguments()[0];
}
返回域类;
}
公共T findById(最终Y id)引发系统异常{
返回(T)this.execute(新的HibernateCallback(){
@凌驾
public T doInHibernate(会话会话)抛出HibernateeException、SQLException{
return(T)session.get(domainClass,id);
}
});
}
}
注意:clientService和clientDAO是SpringBeans对象
我的问题是如何使用hibernate优化循环中的clientService.findById?我觉得findById调用会使循环过程变慢
accountList通常包含7000多条记录,因此我需要类似预编译查询机制的东西,就像jdbc中的PreparedStatements一样。使用hibernate可以做到这一点吗
注意:上面的代码已经通过删除不相关的部分进行了简化,出于隐私原因,方法、变量和类名都是虚构的。如果您发现输入错误,请在注释部分告诉我,因为我是手动键入代码的。在Hibernate/JPA中,您可以使用Hibernate查询语言/JPA查询语言编写查询并创建NamedQuery。在服务器启动时编译NAMEDQUEY,这样您就可以将其视为某种准备好的语句。 您可以尝试编写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();
}
}
@namedquerys({
@NamedQuery(name=“按\u ID查询”,
query=“从某个实体se中选择u,其中se.id位于(:idList)”,
})
类实体{
}
类sometentitydao{
公共列表findIdList(列表idList){
Query Query=entityManager.createNamedQuery(“Query_BY_ID”);
query.setParameter(“idList”,idList);
返回query.getResultList();
}
}
不清楚您想要实现什么。我不会在循环中进行服务调用。为什么不使用命名查询
?
检索附加到给定帐户的所有客户端
,然后迭代该客户端列表
SELECT c from Client c JOIN c.account a WHERE a.id IN (:accounIds)
但这确实取决于业务需求!
我也不清楚你为什么不打电话:
Client client = account.getClient();
您可能希望加载已获取的客户端的accountList。使用即时抓取,或。如果帐户
实体不包含客户
,您应该有很好的理由。我找到了最佳解决方案。我将从表Account和客户机中选择列的查询合并到一个视图(View\u Account\u Client),然后为视图创建实体类(AccountClientView),并使用hibernate获取它,结果是wow,它大大提高了性能。使用真实代码,完成循环可能需要15-20分钟,但使用View,只需要8-10秒
@Entity
@Table(name = "VIEW_ACCOUNT_CLIENT")
public class AccountClientView implements Serializable {
...
}
您好,是的,该帐户不包含客户端属性(您指的是@ManyToOne映射,对吗?)。只有fkClient映射到引用客户端表中主键的外键列。我不知道为什么设计是这样的,因为我不是最初的开发者。使用account.getClient()是否会提高性能?顺便说一句,代码使用带注释的hibernate。我认为我不能使用select join way(select c from Client c join c.account a
),因为循环中同时使用了客户机和帐户实体(参见上面的代码,我已经对其进行了更新)。您好,我尝试添加了getClient()
和setClient())
使用@ManyToOne
到帐户
实体,但我得到了映射异常:帐户列:FK_客户端(应使用insert=“false”update=“false”)映射)
。问题是我无法将insert=“false”update=“false”
添加到get/setFkClient()
中,因为它们已在其他地方使用。我也无法在不中断当前代码的情况下删除get/setFkClient()。您可以尝试将此FkClient
属性设置为瞬态,然后在get/setClient()
中对其进行操作。但我想我无法进一步帮助您,因为我不知道您的整个应用程序和逻辑:(没关系,我找到了最好的解决方案。我将查询放入视图,然后为视图创建实体类并使用hibernate获取它,结果是哇,它大大提高了性能。使用真实代码,完成循环可能需要15-20分钟,但使用View,只需要8-10秒。