InnoDB deadlock with read-uncommited! - Java - Glassfish - EJB3 (JPA/Hibernate)

喜夏-厌秋 提交于 2019-12-06 09:22:28

I don't have an exact answer for your problem, but this may help you narrowing it down.

Deadlocks can happen in any transaction isolation level because innodb will set locks on updates even on "read uncommitted".

You can test this with this simple scenario:

CREATE TABLE locktest (a INT(11), b INT(11), PRIMARY KEY (a)) ENGINE=INNODB;
INSERT INTO locktest VALUE (1, 1);
INSERT INTO locktest VALUE (2, 1);

Then, open 2 mysql consoles (C1 and C2) and run these commands in order:

C1> BEGIN;
C2> BEGIN;
C1> UPDATE locktest SET b = b + 1 WHERE a = 1;
C2> UPDATE locktest SET b = b + 1 WHERE a = 2;
C1> UPDATE locktest SET b = b + 1 WHERE a = 2;
C2> UPDATE locktest SET b = b + 1 WHERE a = 1;

You will see a deadlock on C2, and C1 completing successfully even on read uncommitted. If you check the engine log you will see a similar report.

If you remove the primary key on the table the commands choke even earlier and this is because innodb locking works better if there's an index covering the query that is setting the locks.

So, going back to your problem.

You should check all the queries involved in transactions that ended in deadlocks and make sure that the appropriate indexes exist. If MySQL has to do a full table scan it will end locking more than it needs.

These tips helped me solve some deadlocks in my app. A good way of preventing deadlocks is setting a write lock with "SELECT ... FOR UPDATE" to lock some parent row.

So for example, if you have multiple transactions trying to update some specific customer data you could issue a "SELECT id FROM customer WHERE id=123 FOR UPDATE", they will wait in order at that point instead of ending holding locks that each other needs.

I was having a similar problem with an Java application using an Oracle database.

I found that the database was missing indexes on foreign keys, which caused the database to lock many more rows than required, and led to deadlocks in a highly concurrent test.

Here is a very good article for diagnosing this. Much of the article is oracle-specific, but some things apply to other relational databases too: http://www.oratechinfo.co.uk/deadlocks.html

You should take for granted that deadlocks will happen in any transactional database no matter what you do. You just should handle them gracefully and repeat the failing transaction some fixed number of times (3 normally is ok) - there should be a parameter somewhere in Glassfish responsible for that.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!