Home > database >  Forcing a deadlock with MySQL transactions
Forcing a deadlock with MySQL transactions

Time:02-10

I'm trying to force a deadlock for a demonstration and with Oracle, it seems to be working, but in MySQL, for some reason, the query goes through...

Why is my example not causing a deadlock??

@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();
}

The log goes as following:

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!

CodePudding user response:

Using your code in the repository that you indicted, I have the expected behaviour as you can see in the following image:

enter image description here

I've used MySQL 5.6 (also in the latest version the same occurs).

Also the code in the repository is not the same you posted here. When using the code you posted here the behaviour does not occur.

If you observe closely:

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

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

Is using Ids that do not exist in database.

Your seed database uses IDs "E1" and "E2". In practice you are updating nothing.

Changing your execute statement to

final int update = statement.executeUpdate();

You can see how many records were affected (zero).

So no deadlock occurs.

In your repository code, if you do the same, you will see that one record was updated in each call.

  • Related