简体   繁体   English

使用连接表在多对多休眠中死锁

[英]Deadlock in Hibernate Many-to-Many with join table

I am working on an enterprise application where we use Hibernate and a many-to-many relationship with a join table. 我正在一个企业应用程序上工作,在该应用程序中我们使用了Hibernate并通过一个联接表使用了多对多关系。 We are seeing very sporadic database deadlocks in production (with high volume) that we cannot recreate. 我们看到生产中存在非常零星的数据库死锁(大量),我们无法重新创建死锁。

Category.java Category.java

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

Category.hbm.xml 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没有一组类别,因为这是单向的多对多

The CATEGORY_PRODUCT_ASSC table is a simple join table that only has 2 columns: CATEGORY_ID and PRODUCT_ID . CATEGORY_PRODUCT_ASSC表是一个简单的联接表,只有两列: CATEGORY_IDPRODUCT_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连接表中的插入内容(Category上没有任何更改)

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. 当我们看到死锁时,不可避免地会涉及到update CATEGORY调用。 We need to prevent these update CATEGORY SQL statements from being executed. 我们需要阻止执行这些update 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(因为它没有更改),但是仍然可以将其插入联接表CATEGORY_PRODUCT_ASSC中?

Option 2: If not, we have thought about just doing a straight INSERT of the CATEGORY_PRODUCT_ASSC rows via JDBC. 选项2:如果没有,我们考虑过仅通过JDBC对CATEGORY_PRODUCT_ASSC行进行直接插入。 However, one concern is stale Hibernate objects (Category objects) in the cache. 但是,一个问题是缓存中的Hibernate对象(Category对象)过时。 Any ideas/recommendations on this possible approach? 关于这种可能的方法有什么想法/建议?

Thank you very much in advance for your help. 预先非常感谢您的帮助。 :-) :-)

We resolved this issue. 我们解决了这个问题。 It did turn out to be the update category statement. 事实证明这是update category声明。 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 . 我们没有使用CATEGORY_PRODUCT_ASSC表作为多对多关系的联接,而是创建了一个Hibernate管理的实体来表示该联接表... 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,并发现与旧代码的并发与新代码的并发。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM