diff -u b/core/modules/mysql/src/Driver/Database/mysql/Connection.php b/core/modules/mysql/src/Driver/Database/mysql/Connection.php --- b/core/modules/mysql/src/Driver/Database/mysql/Connection.php +++ b/core/modules/mysql/src/Driver/Database/mysql/Connection.php @@ -219,11 +219,22 @@ // by one. $connection_options += [ 'init_commands' => [], - // @todo Switch to 'READ COMMITTED' for Drupal 10 - // see https://www.drupal.org/node/1650930. - 'isolation_level' => 'REPEATABLE READ', + // @todo Switch to 'READ COMMITTED' for Drupal 10 + // see https://www.drupal.org/node/1650930. + 'isolation_level' => 'REPEATABLE READ', ]; + $isolation_levels = [ + 'READ COMMITTED', + 'REPEATABLE READ', + 'READ UNCOMMITTED', + 'SERIALIZABLE', + ]; + + if (!in_array($connection_options['isolation_level'], $isolation_levels)) { + throw new DatabaseTransactionIsolationLevelException($connection_options['isolation_level']); + } + $connection_options['init_commands'] += [ 'sql_mode' => "SET sql_mode = 'ANSI,TRADITIONAL'", 'isolation' => 'SET SESSION TRANSACTION ISOLATION LEVEL ' . $connection_options['isolation_level'], diff -u b/core/modules/mysql/tests/src/Functional/InstallerIsolationLevelExistingDatabaseSettingsTest.php b/core/modules/mysql/tests/src/Functional/InstallerIsolationLevelExistingDatabaseSettingsTest.php --- b/core/modules/mysql/tests/src/Functional/InstallerIsolationLevelExistingDatabaseSettingsTest.php +++ b/core/modules/mysql/tests/src/Functional/InstallerIsolationLevelExistingDatabaseSettingsTest.php @@ -30,7 +30,7 @@ } // Pre-configure database credentials in settings.php. - unset($connection_info['default']['pdo'], $connection_info['default']['init_commands']); + unset($connection_info['default']['pdo']); $this->settings['databases']['default'] = (object) [ 'value' => $connection_info, @@ -46,7 +46,7 @@ $contents = file_get_contents($this->container->getParameter('app.root') . '/' . $this->siteDirectory . '/settings.php'); // Test that isolation_level were not override. - $this->assertStringNotContainsString("'isolation_level' => 'REPEATABLE READ',", $contents); + $this->assertStringNotContainsString("'isolation_level'", $contents); // Test that transaction level is REPEATABLE-READ. $this->assertEquals('REPEATABLE-READ', $database_connection->query('SELECT @@SESSION.transaction_isolation AS transaction_isolation')->fetch()->transaction_isolation); diff -u b/sites/default/default.settings.php b/sites/default/default.settings.php --- b/sites/default/default.settings.php +++ b/sites/default/default.settings.php @@ -138,11 +138,16 @@ * request as needed. The fourth line creates a new database with a name of * "extra". * - * For MySQL users only, you can change the transaction isolation level using - * 'isolation_level' setting. By default, MySQL will use 'READ COMMITTED'. + * For MySQL, MariaDB or equivalent databases can the option 'isolation_level' + * be set. The recommended option is 'READ COMMITTED'. Existing sites without + * this setting will default to 'REPEATABLE READ'. The other 2 options are + * 'READ UNCOMMITTED' and 'SERIALIZABLE'. They are available, but not supported. + * Use them at your own risk. For more info: + * https://dev.mysql.com/doc/refman/5.7/en/innodb-transaction-isolation-levels.html * * On your settings.php, change the isolation level: * @code + * $databases['default']['default']['isolation_level'] = 'READ COMMITTED'; * $databases['default']['default']['isolation_level'] = 'REPEATABLE READ'; * $databases['default']['default']['isolation_level'] = 'READ UNCOMMITTED'; * $databases['default']['default']['isolation_level'] = 'SERIALIZABLE'; only in patch2: unchanged: --- a/core/assets/scaffold/files/default.settings.php +++ b/core/assets/scaffold/files/default.settings.php @@ -138,6 +138,21 @@ * request as needed. The fourth line creates a new database with a name of * "extra". * + * For MySQL, MariaDB or equivalent databases can the option 'isolation_level' + * be set. The recommended option is 'READ COMMITTED'. Existing sites without + * this setting will default to 'REPEATABLE READ'. The other 2 options are + * 'READ UNCOMMITTED' and 'SERIALIZABLE'. They are available, but not supported. + * Use them at your own risk. For more info: + * https://dev.mysql.com/doc/refman/5.7/en/innodb-transaction-isolation-levels.html + * + * On your settings.php, change the isolation level: + * @code + * $databases['default']['default']['isolation_level'] = 'READ COMMITTED'; + * $databases['default']['default']['isolation_level'] = 'REPEATABLE READ'; + * $databases['default']['default']['isolation_level'] = 'READ UNCOMMITTED'; + * $databases['default']['default']['isolation_level'] = 'SERIALIZABLE'; + * @endcode + * * You can optionally set a prefix for all database table names by using the * 'prefix' setting. If a prefix is specified, the table name will be prepended * with its value. Be sure to use valid database characters only, usually only in patch2: unchanged: --- /dev/null +++ b/core/modules/mysql/src/Driver/Database/mysql/DatabaseTransactionIsolationLevelException.php @@ -0,0 +1,25 @@ +markTestSkipped("This test does not support the {$connection_info['default']['driver']} database driver."); + } + + $connection_info['default']['isolation_level'] = 'INVALID_LEVEL'; + $this->expectException(DatabaseTransactionIsolationLevelException::class); + $this->expectExceptionMessage("The isolation level INVALID_LEVEL is not valid, use one of options available instead."); + + Connection::open($connection_info['default']); + } + +}