简体   繁体   中英

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. We are seeing very sporadic database deadlocks in production (with high volume) that we cannot recreate.

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

The CATEGORY_PRODUCT_ASSC table is a simple join table that only has 2 columns: CATEGORY_ID and 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)

I turn on Hibernate show_sql and see the following:

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.

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 ?

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?

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

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 .

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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