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.