MySQL 8.0 支持對單個數據庫設置只讀!

MySQL 8.0.22 支持對單個數據庫設置只讀,當一個實例中只需要遷移部分數據庫時比較實用,避免數據庫遷移過程中數據庫及其對象被修改。

作者:李富強,愛可生 DBA 團隊成員,熟悉 MySQL,TiDB,OceanBase 等數據庫。相信持續把對的事情做好一點,會有不一樣的收穫。

愛可生開源社區出品,原創內容未經授權不得隨意使用,轉載請聯繫小編並註明來源。

本文約 1600 字,預計閱讀需要 5 分鐘。

新特性概要

對單個數據庫設置只讀狀態,可以通過 ALTER DATABASE 語句中的 READ ONLY 選項來實現,該選項在 MySQL 8.0.22 版本 中引入,用於控制是否允許對數據庫及其對象(包括其定義、數據和元數據)進行寫入操作。

當只需要遷移一個實例當中的 部分 數據庫時,對部分數據庫開啓 READ ONLY,不用擔心數據庫遷移期間這些數據庫被修改。

使用方法

以設置數據庫 lfq 爲只讀狀態舉例,可以觀測到修改數據庫只讀狀態對已建立連接的用戶是立即生效的(即:session1 修改 lfq 數據庫爲只讀,session2lfq 的只讀狀態是立即生效的。)

#session1
 MySQL  localhost:3000 ssl  SQL > select version(),@@port,connection_id();
+-----------+--------+-----------------+
| version() | @@port | connection_id() |
+-----------+--------+-----------------+
| 8.0.22    |   3000 |              22 |
+-----------+--------+-----------------+
1 row in set (0.0015 sec)
 
#session2
 MySQL  localhost:3000 ssl  SQL > select version(),@@port,connection_id();
+-----------+--------+-----------------+
| version() | @@port | connection_id() |
+-----------+--------+-----------------+
| 8.0.22    |   3000 |              24 |
+-----------+--------+-----------------+
1 row in set (0.0009 sec)


#session1,修改前查一下數據庫的只讀狀態,OPTIONS值爲空,代表數據庫非只讀狀態
 MySQL  localhost:3000 ssl  SQL > SELECT * FROM INFORMATION_SCHEMA.SCHEMATA_EXTENSIONS WHERE SCHEMA_NAME = 'lfq';
+--------------+-------------+---------+
| CATALOG_NAME | SCHEMA_NAME | OPTIONS |
+--------------+-------------+---------+
| def          | lfq         |         |
+--------------+-------------+---------+
1 row in set (0.0057 sec)
 
#session1,修改數據庫爲只讀狀態
 MySQL  localhost:3000 ssl  SQL > ALTER SCHEMA lfq READ ONLY = 1;
Query OK, 1 row affected (0.0127 sec)
  
#session1,再次查一下數據庫的只讀狀態,OPTIONS值爲“READ ONLY=1”,數據庫只讀狀態修改成功
 MySQL  localhost:3000 ssl  SQL > SELECT * FROM INFORMATION_SCHEMA.SCHEMATA_EXTENSIONS WHERE SCHEMA_NAME = 'lfq';
+--------------+-------------+-------------+
| CATALOG_NAME | SCHEMA_NAME | OPTIONS     |
+--------------+-------------+-------------+
| def          | lfq         | READ ONLY=1 |
+--------------+-------------+-------------+
1 row in set (0.0048 sec)
  
#session1,在lfq庫中新建一張表測試下,數據庫只讀狀態建表失敗
 MySQL  localhost:3000 ssl  SQL > create table lfq.t1(c1 int primary key,n1 varchar(20) );
ERROR: 3989 (HY000): Schema 'lfq' is in read only mode.
 
#session1,表lfq.my_table插入數據測試(my_table爲提前建的表),數據庫只讀狀態表插入數據失敗
 MySQL  localhost:3000 ssl  lfq  SQL > INSERT INTO my_table (name, age, email) VALUES ('LFQ', 18, 'lfq#actionsky.com');
ERROR: 3989 (HY000): Schema 'lfq' is in read only mode.
 
#session1,表lfq.my_table更新數據測試,數據庫只讀狀態表更新數據失敗
 MySQL  localhost:3000 ssl  lfq  SQL > UPDATE my_table SET age = 30 WHERE name = 'LFQ';
ERROR: 3989 (HY000): Schema 'lfq' is in read only mode.
  
#session1,表lfq.my_table刪除數據測試,數據庫只讀狀態表刪除數據失敗
 MySQL  localhost:3000 ssl  lfq  SQL > DELETE FROM my_table WHERE name = 'LFQ';
ERROR: 3989 (HY000): Schema 'lfq' is in read only mode.
   
#session2,查詢數據庫只讀狀態,數據庫爲只讀狀態,session1修改lfq數據庫爲只讀,session2中lfq的只讀狀態是立即生效的
 MySQL  localhost:3000 ssl  SQL > SELECT * FROM INFORMATION_SCHEMA.SCHEMATA_EXTENSIONS WHERE SCHEMA_NAME = 'lfq';
+--------------+-------------+-------------+
| CATALOG_NAME | SCHEMA_NAME | OPTIONS     |
+--------------+-------------+-------------+
| def          | lfq         | READ ONLY=1 |
+--------------+-------------+-------------+
1 row in set (0.0016 sec)
 
#session2,在lfq庫中新建一張表測試下,數據庫爲只讀狀態下建表失敗
 MySQL  localhost:3000 ssl  SQL > create table lfq.t1(c1 int primary key,n1 varchar(20) );
ERROR: 3989 (HY000): Schema 'lfq' is in read only mode.

查詢 READ ONLY 狀態

方法一

通過查詢 INFORMATION_SCHEMA.SCHEMATA_EXTENSIONS 表(在 MySQL 8.0.22 版本引入),輸出結果中如果 OPTIONS 列的值爲 READ ONLY=1,則說明數據庫爲只讀狀態,如果 OPTIONS 列的值爲空,則說明數據庫爲非只讀狀態。

MySQL  localhost:3000 ssl  SQL > select version(),@@port;
+-----------+--------+
| version() | @@port |
+-----------+--------+
| 8.0.22    |   3000 |
+-----------+--------+
1 row in set (0.0029 sec)
MySQL  localhost:3000 ssl  SQL > ALTER SCHEMA lfq READ ONLY = 1;
Query OK, 1 row affected (0.0098 sec)
 MySQL  localhost:3000 ssl  SQL >
 MySQL  localhost:3000 ssl  SQL >
 MySQL  localhost:3000 ssl  SQL >
 MySQL  localhost:3000 ssl  SQL > SELECT * FROM INFORMATION_SCHEMA.SCHEMATA_EXTENSIONS WHERE SCHEMA_NAME = 'lfq';
+--------------+-------------+-------------+
| CATALOG_NAME | SCHEMA_NAME | OPTIONS     |
+--------------+-------------+-------------+
| def          | lfq         | READ ONLY=1 |
+--------------+-------------+-------------+
1 row in set (0.0063 sec)
 MySQL  localhost:3000 ssl  SQL > ALTER SCHEMA lfq READ ONLY = 0;
Query OK, 1 row affected (0.0098 sec)
 MySQL  localhost:3000 ssl  SQL > SELECT * FROM INFORMATION_SCHEMA.SCHEMATA_EXTENSIONS WHERE SCHEMA_NAME = 'lfq';
+--------------+-------------+---------+
| CATALOG_NAME | SCHEMA_NAME | OPTIONS |
+--------------+-------------+---------+
| def          | lfq         |         |
+--------------+-------------+---------+
1 row in set (0.0017 sec)

方法二

通過 SHOW CREATE DATABASE 語句查看,如果輸出結果中帶關鍵字 READ ONLY=1,則表明數據庫爲只讀狀態。

MySQL  localhost:3000 ssl  SQL > ALTER SCHEMA lfq READ ONLY = 1;
Query OK, 1 row affected (0.0118 sec)
 MySQL  localhost:3000 ssl  SQL >  show create database lfq;
+----------+--------------------------------------------------------------------------------------------------------------------------------------------+
| Database | Create Database                                                                                                                            |
+----------+--------------------------------------------------------------------------------------------------------------------------------------------+
| lfq      | CREATE DATABASE `lfq` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin */ /*!80016 DEFAULT ENCRYPTION='N' */ /* READ ONLY = 1 */ |
+----------+--------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.0011 sec)
 MySQL  localhost:3000 ssl  SQL > ALTER SCHEMA lfq READ ONLY = 0;
Query OK, 1 row affected (0.0108 sec)
 MySQL  localhost:3000 ssl  SQL >  show create database lfq;
+----------+------------------------------------------------------------------------------------------------------------------------+
| Database | Create Database                                                                                                        |
+----------+------------------------------------------------------------------------------------------------------------------------+
| lfq      | CREATE DATABASE `lfq` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin */ /*!80016 DEFAULT ENCRYPTION='N' */ |
+----------+------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.0023 sec)

使用限制以及注意事項

  1. READ ONLY 選項不能用在 mysql, information_schema, performance_schema 等系統數據庫上。
MySQL  localhost:3000 ssl  SQL > ALTER SCHEMA mysql READ ONLY = 1 ;
ERROR: 3552 (HY000): Access to system schema 'mysql' is rejected.
  1. ALTER DATABASE 語句不能同時指定多個不同值的 READ ONLY 選項,否則會報錯。
MySQL  localhost:3000 ssl  SQL > ALTER SCHEMA lfq READ ONLY = 1 READ ONLY = 0;
ERROR: 1302 (HY000): Conflicting declarations: 'READ ONLY=0' and 'READ ONLY=1'
  1. ALTER DATABASE 語句在 READ ONLY 選項和其他選項混用時且 READ ONLY 設置爲 1,執行 ALTER DATABASE 語句前如果數據庫的 READ ONLY = 1,則修改報錯。
MySQL  localhost:3000 ssl  SQL > ALTER SCHEMA lfq READ ONLY = 1 ;
Query OK, 1 row affected (0.0141 sec)
 MySQL  localhost:3000 ssl  SQL > SELECT * FROM INFORMATION_SCHEMA.SCHEMATA_EXTENSIONS WHERE SCHEMA_NAME = 'lfq';
+--------------+-------------+-------------+
| CATALOG_NAME | SCHEMA_NAME | OPTIONS     |
+--------------+-------------+-------------+
| def          | lfq         | READ ONLY=1 |
+--------------+-------------+-------------+
1 row in set (0.0069 sec)
 MySQL  localhost:3000 ssl  SQL > ALTER DATABASE lfq READ ONLY = 1 DEFAULT COLLATE utf8mb4_bin;
ERROR: 3989 (HY000): Schema 'lfq' is in read only mode.
  • ALTER DATABASE 語句會等待該數據庫中正在更改的對象的併發事務都已提交後才能執行,反過來也一樣,數據庫中正在更改的對象的併發事務的執行,需要等待 ALTER DATABASE 語句執行完成。

  • 對於只讀數據庫,SHOW CREATE DATABASE 生成的語句包含帶註釋的 READ ONLY 選項(/* READ ONLY = 1 */),使用邏輯備份工具 mysqldump 或者 mysqlpump 備份只讀數據庫,通過備份文件恢復出來的數據庫不是隻讀的,如果恢復後需要只讀,則需要手動執行 ALTER DATABASE 語句設置數據庫爲只讀。

例外情況

不受數據庫只讀狀態的約束。

  • 作爲 MySQL 服務初始化,重啓,升級,複製功能中的一部分執行的語句。
  • 在服務器啓動時由 init_file 系統變量命名的文件中的語句。
  • 可以在只讀數據庫中創建、更改、刪除和寫入臨時表(TEMPORARY 表。)

更多技術文章,請訪問:https://opensource.actionsky.com/

關於 SQLE

SQLE 是一款全方位的 SQL 質量管理平臺,覆蓋開發至生產環境的 SQL 審覈和管理。支持主流的開源、商業、國產數據庫,爲開發和運維提供流程自動化能力,提升上線效率,提高數據質量。

SQLE 獲取

類型 地址
版本庫 https://github.com/actiontech/sqle
文檔 https://actiontech.github.io/sqle-docs/
發佈信息 https://github.com/actiontech/sqle/releases
數據審覈插件開發文檔 https://actiontech.github.io/sqle-docs/docs/dev-manual/plugins/howtouse
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章