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

发布于 2024-07-24 09:17:40 字数 2109 浏览 3 评论 0原文

让我们先设置问题。

我拥有的是 > 4 个表:客户、地址、订单、订单项。 每个都使用 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);

在两个客户对象上运行 a。 这最终会创建大量的选择语句,这些语句获取所有关联的对象(即 OrderItems、Products、ProductType、ProductPricingTmpl 等)。

我需要删除这些选择! 如果它们不存在,查询就会看起来正常并且高效! 更新输出的查询是完美且动态的。

有任何想法吗?

Lets setup the question first.

What I have is >4 tables: Customer, Address, Order, OrderItems. Each are mapped using Hibernate Annotations and accessed through a Spring DAO/Services layer.

What I am trying to do is merge duplicate customers together. So all that really needs to happen is all orders and addresses associated with customer B, need to update their customer_id foreign key to point to customer A. Then customer B must have its disabled bit set.

Instead of sending these simple queries to our database, hibernate goes crazy and issues a ton of select then update queries. Particularly it selects all order items attached to an order (because this is defined EAGER, and this point is not changeable.). To get the selects before update to stop happening I tried adding the hibernate entity annotation on top of the regular javax.persistence.Entity like:

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

this seemed to have no affect, except with simple queries where it only updated single items in a table.

I get the objects using the following hibernate criteria:

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

Then i move all of the address and order objects from customer B to customer A and run a

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

on both customer objects. This ends up creating a ton of select statements that get all of the associated objects (i.e. OrderItems, Products, ProductType, ProductPricingTmpl, etc..)

I need to get these selects removed! If they were not there the query would look normal and be efficient! The Update outputted queries are perfect and dynamic.

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

夕嗳→ 2024-07-31 09:17:41

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

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

因此,您将强制 Hibernate 在修改数据之前加载所有数据。

尝试不同的操作,例如 update() :

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

不过,没有任何承诺,Hibernate 可能会决定无论如何都需要加载它。 dynamicUpdates=true 配置实际上可能会让情况变得更糟,因为它需要知道要启动什么才能发出动态更新。

The clue might be in your choice of merge() operation. From the Hibernate javadoc:

Copy the state of the given object
onto the persistent object with the
same identifier. If there is no
persistent instance currently
associated with the session, it will
be loaded.

So you're forcing Hibernate to load all of the data in before modifying it.

Try a different operation, such as update() :

Update the persistent instance with
the identifier of the given detached
instance.

No promises, though, Hibernate might decide it needs to load it in anyway. The dynamicUpdates=true config might actually make it worse, since it needs to know what's there to start before it can issue dynamic updates.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文