让Hibernate做简单的更新,而不是大量选择然后更新

时间:2009-06-17 21:02:19

标签: sql hibernate query-optimization sql-update

让我们先设置问题。

我拥有的是> 4个表:Customer,Address,Order,OrderItems。每个都使用Hibernate Annotations进行映射,并通过Spring DAO / Services层进行访问。

我想要做的是将重复的客户合并在一起。因此,真正需要发生的是与客户B相关的所有订单和地址,需要更新其customer_id外键以指向客户A.然后客户B必须设置其禁用位。

而不是将这些简单的查询发送到我们的数据库,hibernate变得疯狂并发出大量的选择然后更新查询。特别是它选择附加到订单的所有订单商品(因为这是定义EAGER,并且此点不可更改。)。为了在更新之前获得选择以停止发生,我尝试在常规javax.persistence.Entity之上添加hibernate实体注释,如:

@org.hibernate.annotations.Entity(dynamicUpdate = true, selectBeforeUpdate = false, dynamicInsert = true)

这似乎没有任何影响,除了简单的查询,它只更新表中的单个项目。

我使用以下休眠标准获取对象:

            Criteria c1 = null;
            Criteria c2 = null;
            Criteria c = session.createCriteria(Customer.class);
            c.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);

            if(resultLimit>0) c.setMaxResults(resultLimit);
            if(timeout>0) c.setTimeout(timeout);
            for(String filter: sqlFilters) {
                if(filter.indexOf("{alias}.customer_")!=-1) c.add(Restrictions.sqlRestriction(filter));
                else if(filter.indexOf("{alias}.address_")!=-1 && addrsAttached) {
                    if(c1==null)
                        c1 = c.createCriteria("addresses").setFetchMode("type", FetchMode.JOIN);
                    c1.add(Restrictions.sqlRestriction(filter));
                } else if(filter.indexOf("{alias}.order_")!=-1 && ordersAttached) {
                    if(c2==null)
                        c2 = c.createCriteria("orders").setFetchMode("orderItems", FetchMode.SELECT);
                    c2.add(Restrictions.sqlRestriction(filter));
                }
            }
            return (List<Customer>) c.list();

然后我将所有地址和订单对象从客户B移动到客户A并运行

return (Customer) this.getHibernateTemplate().merge(customer);

两个客户对象。这最终会创建大量的select语句来获取所有相关对象(即OrderItems,Products,ProductType,ProductPricingTmpl等)。

我需要删除这些选择!如果他们不在那里,查询看起来很正常并且效率很高!更新输出的查询是完美和动态的。

有什么想法吗?

1 个答案:

答案 0 :(得分:2)

线索可能在您选择的merge()操作中。来自Hibernate javadoc:

  

复制给定对象的状态   用它来到持久对象上   相同的标识符如果没有   目前持久化实例   与会话相关联,它会   加载。

所以你在强制修改它之前强迫Hibernate加载所有数据。

尝试其他操作,例如update():

  

使用更新持久化实例   给定分离的标识符   实例

但是,没有承诺,Hibernate可能会决定是否需要加载它。 dynamicUpdates = true config实际上可能会让它变得更糟,因为它需要知道在发布动态更新之前要启动什么。