用 MySQL 个事务强制死锁

Forcing a deadlock with MySQL transactions

我正在尝试为演示和 Oracle 强制造成死锁,它似乎有效,但在 MySQL 中,出于某种原因,查询通过...

为什么我的例子没有导致死锁?

@EventListener(ApplicationReadyEvent.class)
public void executeStartupTask() throws Exception {
    LOGGER.info("Connecting to MySQL via: " + databaseUrl);
    LOGGER.info("Seeding database...");
    seedDatabase();

    Thread providerResetThread = new Thread(() -> {
        try {
            Connection connection = getMySQLDataSource().getConnection();
            connection.setAutoCommit(false);

            // 1st device model always GMETER
            updateDeviceModel("E000000001", "GMETER", connection);

            LOGGER.info("Sleep for " + genericTimeoutLength + "  milliseconds");
            Thread.sleep(Integer.parseInt(genericTimeoutLength));

            // 2st device model always EMETER
            updateDeviceModel("E000000002", "EMETER",  connection);

            connection.commit();
        }
        catch(Exception e) {
            e.printStackTrace();
        }
    });

    providerResetThread.start();

    // Resetting the model type
    try {
        Connection connection = getMySQLDataSource().getConnection();
        connection.setAutoCommit(false);

        Statement statement = connection.createStatement();

        updateDeviceModel("E000000002", "NONE", connection);
        updateDeviceModel("E000000001", "NONE", connection);

        connection.commit();
    }
    catch(Exception e) {
        e.printStackTrace();
    }

    providerResetThread.join();
    LOGGER.info("EXECUTION SUCCESSFUL!");
}


public void updateDeviceModel(String deviceId, String model, Connection connection) throws SQLException {
    LOGGER.info("Updating model for device " + deviceId);
    PreparedStatement statement = connection.prepareStatement("UPDATE device_entity SET model = '" + model + "' WHERE deviceId = '" + deviceId + "'");
    statement.execute();
}

日志如下:

2022-02-08 09:59:32,950 INFO  method: [Thread-2] interview.InterviewApplication (InterviewApplication.java:126) - Updating model for device E000000001
2022-02-08 09:59:32,950 INFO  method: [main] interview.InterviewApplication (InterviewApplication.java:126) - Updating model for device E000000002
2022-02-08 09:59:32,955 INFO  method: [Thread-2] interview.InterviewApplication (InterviewApplication.java:56) - Sleep for 5000  milliseconds
2022-02-08 09:59:37,965 INFO  method: [Thread-2] interview.InterviewApplication (InterviewApplication.java:126) - Updating model for device E000000002
2022-02-08 09:59:37,975 INFO  method: [main] interview.InterviewApplication (InterviewApplication.java:126) - Updating model for device E000000001
2022-02-08 09:59:43,046 INFO  method: [main] interview.InterviewApplication (InterviewApplication.java:92) - EXECUTION SUCCESSFUL!

使用您指定的存储库中的代码,我得到了预期的行为,如下图所示:

我用过 MySQL 5.6(在最新版本中也是如此)。

此外,存储库中的代码与您在此处发布的代码不同。使用您在此处发布的代码时,不会发生这种行为。

仔细观察的话:

updateDeviceModel("E000000001", "GMETER", connection);

updateDeviceModel("E000000001", "NONE", connection);

正在使用数据库中不存在的 ID。

您的种子数据库使用 ID“E1”和“E2”。 实际上你没有更新任何东西。

将您的执行语句更改为

final int update = statement.executeUpdate();

您可以看到有多少记录受到影响(零)。

所以不会出现死锁。

在您的存储库代码中,如果您执行相同的操作,您将看到每次调用都更新了一条记录。