Hibernate中的死锁多对多与联接表

时间:2021-11-26 07:07:53

I am working on an enterprise application where we use Hibernate and a many-to-many relationship with a join table. We are seeing very sporadic database deadlocks in production (with high volume) that we cannot recreate.

我正在开发一个企业应用程序,我们使用Hibernate和连接表的多对多关系。我们看到生产中非常零星的数据库死锁(具有高容量),我们无法重新创建。

Category.java

public class Category {
    ....
    private Set<Product> products = new HashSet<Product>();
    ...
}

Category.hbm.xml

<class 
    name="Category"
    table="CATEGORY"
>
    ...
   <!-- uni-directional many-to-many association to Product -->
   <set
       name="products"
       table="CATEGORY_PRODUCT_ASSC"
       lazy="false"
       cascade="none"
    >
        <key column="CATEGORY_ID" />
        <many-to-many class="Product" column="PRODUCT_ID" />
    </set>
</class> 

Product.java, Product.hbm.xml do not have a set of Categories, as this is uni-directional many-to-many

Product.java,Product.hbm.xml没有一组Categories,因为这是单向的多对多

The CATEGORY_PRODUCT_ASSC table is a simple join table that only has 2 columns: CATEGORY_ID and PRODUCT_ID.

CATEGORY_PRODUCT_ASSC表是一个简单的连接表,只有2列:CATEGORY_ID和PRODUCT_ID。

Right now, we are calling Session.saveOrUpdate on the Category instance object for the sole purpose of getting the inserts in the CATEGORY_PRODUCT_ASSC join table (nothing changed on the Category)

现在,我们在Category实例对象上调用Session.saveOrUpdate,其唯一目的是在CATEGORY_PRODUCT_ASSC连接表中获取插入(类别上没有任何更改)

I turn on Hibernate show_sql and see the following:

我打开Hibernate show_sql并看到以下内容:

update CATEGORY set NAME=?, DESCRIPTION=?, where category_id=?
insert into CATEGORY_PRODUCT_ASSC (CATEGORY_ID, PRODUCT_ID) values (?, ?)

The problem is that we have many products being created at the exact same second on multiple servers, all for the same Category.

问题是我们在多个服务器上以完全相同的秒创建了许多产品,所有产品都属于同一类别。

When we see deadlocks, the update CATEGORY call is inevitably involved. We need to prevent these update CATEGORY SQL statements from being executed.

当我们看到死锁时,不可避免地会涉及更新CATEGORY调用。我们需要阻止执行这些更新CATEGORY SQL语句。

Option 1: Is there any way that I can call Session.saveOrUpdate(category) and have it not update Category (since that has not changed), but still do the insert into the join table CATEGORY_PRODUCT_ASSC ?

选项1:有什么方法可以调用Session.saveOrUpdate(类别)并让它不更新Category(因为它没有改变),但仍然插入到连接表CATEGORY_PRODUCT_ASSC?

Option 2: If not, we have thought about just doing a straight INSERT of the CATEGORY_PRODUCT_ASSC rows via JDBC. However, one concern is stale Hibernate objects (Category objects) in the cache. Any ideas/recommendations on this possible approach?

选项2:如果没有,我们考虑过只通过JDBC直接插入CATEGORY_PRODUCT_ASSC行。但是,一个问题是缓存中陈旧的Hibernate对象(Category对象)。关于这种可能方法的任何想法/建议?

Thank you very much in advance for your help. :-)

非常感谢您的帮助。 :-)

1 个解决方案

#1


0  

We resolved this issue. It did turn out to be the update category statement. Instead of using the CATEGORY_PRODUCT_ASSC table as a join-through for the many-to-many relationship, we created a Hibernate-managed entity that represents this join table ... CategoryProductAssc.

我们解决了这个问题。它确实是更新类别声明。我们创建了一个代表此连接表的Hibernate管理实体,而不是使用CATEGORY_PRODUCT_ASSC表作为多对多关系的连接... CategoryProductAssc。

This way, we could directly persist the relationship without having to call Session.saveOrUpdate on the Category instance object for the sole purpose of getting the inserts in the CATEGORY_PRODUCT_ASSC join table when nothing changed on the Category object.

这样,我们可以直接持久保持关系,而无需在Category实例对象上调用Session.saveOrUpdate,其唯一目的是在Category对象上没有任何更改时获取CATEGORY_PRODUCT_ASSC连接表中的插入。

I created Cactus tests that spun up 20 simultaneous executions, tested old vs new code and our DBAs monitored and saw concurrency with the old code and no concurrency with the new code.

我创建了Cactus测试,它们实现了20个同步执行,测试了旧代码和新代码,我们的DBA受到监控,看到了旧代码的并发性,并且新代码没有并发性。

#1


0  

We resolved this issue. It did turn out to be the update category statement. Instead of using the CATEGORY_PRODUCT_ASSC table as a join-through for the many-to-many relationship, we created a Hibernate-managed entity that represents this join table ... CategoryProductAssc.

我们解决了这个问题。它确实是更新类别声明。我们创建了一个代表此连接表的Hibernate管理实体,而不是使用CATEGORY_PRODUCT_ASSC表作为多对多关系的连接... CategoryProductAssc。

This way, we could directly persist the relationship without having to call Session.saveOrUpdate on the Category instance object for the sole purpose of getting the inserts in the CATEGORY_PRODUCT_ASSC join table when nothing changed on the Category object.

这样,我们可以直接持久保持关系,而无需在Category实例对象上调用Session.saveOrUpdate,其唯一目的是在Category对象上没有任何更改时获取CATEGORY_PRODUCT_ASSC连接表中的插入。

I created Cactus tests that spun up 20 simultaneous executions, tested old vs new code and our DBAs monitored and saw concurrency with the old code and no concurrency with the new code.

我创建了Cactus测试,它们实现了20个同步执行,测试了旧代码和新代码,我们的DBA受到监控,看到了旧代码的并发性,并且新代码没有并发性。