安装完Drupal10,细心的用户可能在后台状态报告页面看到如下的警告信息:
Database Isolation Level REPEATABLE-READ
For the best performance and to minimize locking issues, the READ-COMMITTED transaction isolation level is recommended.
翻译过来就是 数据库隔离级别 REPEATABLE-READ 为了获得最佳性能并最大程度地减少锁定问题,建议使用 READ-COMMIT 事务隔离级别。
首先了解一下数据库事务的基本概念。
一、数据库事务的基本要素(ACID):
1.原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。
2.一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。
3.隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
4.持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。
二、数据库事务的并发问题:
1.脏读
脏读是指一个事务正在访问数据,并且对数据进行了修改,但是这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
2.不可重复读
不可重复读是指在一个事务内,多次读取同一个数据。
在这个事务还没有结束时,另外一个事务也访问了该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
3.幻读
幻读是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
为了解决以上这些问题,数据库都会有事务隔离级别的概念。
事务的隔离级别的作用就是让事务之间互相隔离,互不影响,确保事务的一致性。如果事务没有隔离性,就容易出现脏读、不可重复读和幻读等情况。
MySQL定义了4类事务隔离级别,用来指定事务中的哪些数据改变是可见的,哪些数据改变是不可见的,不同事务隔离级别可能产生的问题如下表所示:
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
读未提交(READ-UNCOMITTED) | 是 | 是 | 是 |
不可重复读(READ-COMMITTED) | 否 | 是 | 是 |
可重复读(REPEATABLE-READ) | 否 | 否 | 是 |
串行化(SERIALIZABLE) | 否 | 否 | 否 |
隔离级别由低到高分别为 READ-UNCOMITTED、READ-COMMITTED、REPEATABLE-READ、SERIALIZABLE。低级别的隔离级别可以支持更高的并发处理,同时占用的系统资源更少。
MySQL和MariaDB默认的事务隔离级别为REPEATABLE-READ。
回到Drupal10的问题上,根据Drupal官方文档介绍,当使用MySQL/MariaDB数据库时,如果数据库隔离级别为默认的REPEATABLE-READ可能会导致数据库表被死锁,网站会因此变得非常缓慢或没有响应,所以Drupal官方推荐使用Drupal10站点的数据库事务隔离级别改为 READ-COMMITTED,避免数据库表死锁和提升性能。
有两种方法可以将MySQL的事务隔离级别更改为“READ-COMMITTED”。
方法一:
用MySQL超级用户(一般为root)登录MySQL控制台,运行以下命令:
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
这个命令将为数据库上的每个会话的事务隔离级别设置为READ-COMMITTED,这也是Drupal官方推荐的方法。
方法二:
更改Drupal10的配置文件,默认路径为: /web/sites/default/settings.php。
在文件末尾找到如下的数据库信息:
$databases['default']['default'] = array (
'database' => 'atuwe_com',
'username' => 'root',
'password' => '1234567890',
'prefix' => '',
'host' => 'localhost',
'port' => '3306',
'namespace' => 'Drupal\\mysql\\Driver\\Database\\mysql',
'driver' => 'mysql',
'autoload' => 'core/modules/mysql/src/Driver/Database/mysql/',
);
将以下代码添加到数据库信息 ); 的前面:
'init_commands' => [
'isolation_level' => 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED',
],
添加后的数据库信息如下:
$databases['default']['default'] = array (
'database' => 'atuwe_com',
'username' => 'root',
'password' => '1234567890',
'prefix' => '',
'host' => 'localhost',
'port' => '3306',
'namespace' => 'Drupal\\mysql\\Driver\\Database\\mysql',
'driver' => 'mysql',
'autoload' => 'core/modules/mysql/src/Driver/Database/mysql/',
'init_commands' => [
'isolation_level' => 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED',
],
);
然后进入Drupal10后台 配置 > 性能 > 清空所有缓存,再进入状态报告页面就可以看到 Database Isolation Level 已更改为 READ-COMMITTED,数据库事物隔离的警告已经消失。