Backend Development 8 min read

Why JVM Locks Can Deadlock with MySQL Row Locks—and How to Fix Them

This article explains how JVM synchronized locks and MySQL row locks can interact to cause deadlocks, demonstrates the problem with sample Spring code, shows the resulting lock‑wait timeout exception, and provides a refactoring solution to avoid the deadlock.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Why JVM Locks Can Deadlock with MySQL Row Locks—and How to Fix Them

1. Introduction

In multithreaded programming, locks ensure data consistency and prevent concurrent access issues. JVM locks (synchronized) and MySQL row locks are common mechanisms that can lead to deadlocks when used together. This article examines whether they can cause deadlocks, analyzes the reasons, and offers solutions.

2. Lock Overview

JVM Lock

JVM locks are built‑in synchronization mechanisms implemented via the synchronized keyword. They protect critical sections so that only one thread can execute the protected code at a time. Each object has an associated monitor lock; a thread must acquire the monitor before entering the synchronized block.

MySQL Row Lock

MySQL row locks protect individual rows in InnoDB tables, preventing multiple transactions from modifying or deleting the same row simultaneously. The lock granularity depends on the indexes used; primary‑key indexes lock a single row, while non‑unique indexes may lock multiple rows.

3. Example Code

The following Spring service demonstrates two operations: batch deletion and single‑row update, both wrapped with @Transactional and synchronized blocks.

<code>static class PersonService {
    @Resource
    private JdbcTemplate jdbcTemplate;
    @Resource
    private DataSource dataSource;
    @Resource
    private DataSourceTransactionManager tm;

    // batch delete
    @Transactional
    public void batcherOperator() {
        IntStream.of(1, 2, 3).forEach(id -> {
            delete(id);
        });
    }
    private void delete(int id) {
        synchronized (this) {
            this.jdbcTemplate.update("delete from t_person where id = ?", id);
        }
    }

    // update with lock
    @Transactional
    public synchronized void update(int id) {
        // other operations
        this.jdbcTemplate.update("update t_person t set t.name = 'xxx' where t.id = 1");
    }
}
</code>

Running two threads—one executing batcherOperator() and the other executing update(1) —may not immediately show a problem, but after adding a sleep when deleting id = 2 , a lock‑wait timeout occurs:

<code>org.springframework.dao.CannotAcquireLockException: StatementCallback; SQL [update t_person t set t.name = 'xxx' where t.id = 1]; Lock wait timeout exceeded; try restarting transaction; nested exception is com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
</code>

4. Visualizing the Deadlock

The following screenshots illustrate the lock waiting in two MySQL sessions.

The timeline diagram below shows how the JVM lock held during the delete of id = 2 blocks the update transaction, leading to a deadlock between the JVM monitor and the MySQL row lock.

5. Optimizing the Code

Moving the synchronized block outside the loop eliminates the deadlock:

<code>@Transactional
public void batcherOperator() {
    synchronized (this) {
        IntStream.of(1, 2, 3).forEach(id -> {
            delete(id);
            if (id == 2) {
                try { TimeUnit.SECONDS.sleep(2); } catch (Exception e) { e.printStackTrace(); }
            }
        });
    }
}
</code>

After this change, the deadlock disappears, though other concurrency issues may still exist.

6. Conclusion

Understanding the interaction between JVM synchronized locks and MySQL row locks helps developers avoid deadlocks in concurrent applications. Proper lock scope and awareness of database lock behavior are essential for building efficient, stable backend systems.

JavaJVMconcurrencydeadlockMySQLdatabase locks
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.