MySQL 常見錯誤


1. Too many connections

ERROR 1040 (HY000): Too many connections

導致結果:

連接數過多,導致連接不上數據庫,業務無法正常進行

該錯誤發生在有max_connections個客戶連接了mysqld服務器, 應該重啟mysqld, 用更大的max_connections變量值

#默認連接數
mysql> show variables like '%max_connection%';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 151   |
+-----------------+-------+
1 row in set (0.00 sec)

  

解決問題思路:

1、首先先要考慮在我們 MySQL 數據庫參數文件里面,對應的 max_connections 這個參數值是不是設置的太小了,導致客戶端連接數超過了數據庫所承受的最大值。

  • 該值默認大小是 151,可以根據實際情況進行調整。

  • 對應解決辦法:set global max_connections=500

這樣調整會有隱患,因為我們無法確認數據庫是否可以承擔這么大的連接壓力,就好比原來一個人只能吃一斤牛肉,但現在卻非要讓他吃 10斤牛肉,他肯定接受不了。反應到服務器上面,就有可能會出現宕機的可能。

所以這又反映出了,在新上線一個業務系統的時候,要做好壓力測試。保證后期對數據庫進行優化調整。

2. Packet too large

結果:

如果寫入大數據時,因為默認的配置太小,插入和更新操作會因為 max_allowed_packet 參數限制,而導致失敗。

mysql根據max_allowed_packet參數來限制server接受的數據包大小。

當一個MySQL客戶或mysqld服務器得到一個max_allowed_packet個字節長的包, 它發出一個Packet too large錯誤並終止連接。

mysql> show variables like 'max_allowed_packet';
+--------------------+---------+
| Variable_name      | Value   |
+--------------------+---------+
| max_allowed_packet | 4194304 |
+--------------------+---------+

默認是4M大小

可以使用mysqld的命令行選項設置max_allowed_packet為一個更大的尺寸。 例如, 如果將一個全長的BLOB存入一張表中, 需要用max_allowed_packet=24M選項來啟動mysql。

Max_allowed_packet的取值范圍是1024B~1GB

當然不要亂設置,根據具體環境要求,設置太大業務

# 具體設置max_allowed_packet大小
mysql> set @@global.max_allowed_packet=
#在my.cnf 加入這個 
max_allowed_packet= 10M

 

3. 線上要修改mysql參數,怎么避免mysql 重啟

首先確定改參數是動態參數還是靜態參數

如果是靜態參數還是要重啟服務才會生效,動態參數則不用

這時候要修改全局變量, 必須要顯示指定"GLOBAL"或者"@@global.", 同時必須要有SUPER權限.

例如修改最大連接數

#默認連接數
mysql> show variables like '%max_connection%';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 151   |
+-----------------+-------+
1 row in set (0.00 sec)

#修改連接數為500
mysql> set @@global.max_connections=500;
Query OK, 0 rows affected (0.00 sec)

#查看是否修改成功
mysql> show variables like '%max_connection%';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 500   |
+-----------------+-------+

# 在my.cnf 的[mysqld]下面加上 max_connections=500就可以了,也不用重啟服務

  

4. root密碼忘了怎么辦

 

忘記了MySQL的root用戶的口令 在my.cnf中添加skip-grant-tables=1選項重啟mysqld

[root@mysql-150 ~]# mysql -u root -h 127.0.0.1
mysql> flush privileges;
mysql> grant all privileges on *.* to root@'localhost' identified by '456789';
mysql> exit
# 在my.cnf 將skip-grant-tables=1選項去掉
# 重啟mysqld之后就可以用最新的密碼登錄
[root@mysql-150 ~]# vim /etc/my.cnf
[root@mysql-150 ~]# service mysql restart
Shutting down MySQL............ SUCCESS! 
Starting MySQL. SUCCESS! 
[root@mysql-150 ~]# mysql -u root -p456789 -h 127.0.0.1

  

5. 賬號被鎖定

# 創建一個用戶
mysql> create user keme@'localhost' identified by '123456';
# 給一個只讀權限
mysql> grant select on *.* to keme@'localhost';

# 可以從本地登錄
[root@mysql-150 ~]# mysql -u keme -p123456

# 把keme@'localhost' 給lock住,不讓其使用
mysql> alter user keme@'localhost' account lock;

# 在看看能不能從本地登錄
[root@mysql-150 ~]# mysql -u keme -p123456
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 3118 (HY000): Access denied for user 'keme'@'localhost'. Account is locked.

# 查看該用戶是否鎖定
mysql> select host,user,account_locked from mysql.user where user='keme';
+-----------+------+----------------+
| host      | user | account_locked |
+-----------+------+----------------+
| localhost | keme | Y              |
+-----------+------+----------------+
Y已鎖定
# 然后解鎖該keme用戶
mysql> alter user keme@'localhost' account unlock;

# 再去登錄keme用戶
[root@mysql-150 ~]# mysql -u keme -p123456

  

6. 環境變量未設置

例如執行: mysqldump提示: -bash: command not found 是 環境變量設置的問題

 

臨時添加:

# 首先要確定mysql 的安裝位置
shell> export PATH=$PATH:/usr/local/mysql/bin

  

永久設置:

# 在/etc/profile 中末尾添加
PATH=$PATH:$HOME/bin:/usr/local/mysql/bin
export PATH
保存退出后執行: source /etc/bash_profile即可。

  

7. SQL MODE

MySQL服務器可以以不同的SQL模式來操作, 並且可以為不同客戶端應用不同模式。 這樣每個應用程序可以根據自己的需求來定制服務器的操作模式

模式定義MySQL應支持哪些SQL語法, 以及應執行哪種數據驗證檢查。 這樣可以更容易地在不同的環境中使用MySQL, 並結合其它數據庫服務器使用MySQL。

查看當前的sql_mode

mysql> show variables like 'sql_mode';
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| Variable_name | Value                                                                                                                                     |
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| sql_mode      | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> select @@sql_mode;
+-------------------------------------------------------------------------------------------------------------------------------------------+
| @@sql_mode                                                                                                                                |
+-------------------------------------------------------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+-------------------------------------------------------------------------------------------------------------------------------------------+

  

7.1 主要的SQL_Mode值包括:

  • ANSI

更改語法和行為, 使其更符合標准SQL。

  • STRICT_TRANS_TABLES
  • TRADITIONAL

使MySQL的行為象“傳統”SQL數據庫系統。 該模式的簡單描述是當在列中插入不正確的值時“給 出 錯誤 而不是警告” 等同STRICT_TRANS_TABLES、 STRICT_ALL_TABLES、NO_ZERO_IN_DATE、 NO_ZERO_DATE、 ERROR_FOR_DIVISION_BY_ZERO、 NO_AUTO_CREATE_USER。

sql mode常用值

  •  ONLY_FULL_GROUP_BY

對於GROUP BY聚合操作,如果在SELECT中的列,沒有在GROUP BY中出現,那么這個SQL是不合法的,因為列不在GROUP BY從句中

但這有個條件:如果查詢是主鍵列或是唯一索引且非空列,分組列根據主鍵列或者唯一索引且空(null)則sql 分組查詢有效

  • NO_AUTO_VALUE_ON_ZERO

 該值影響自增長列的插入。默認設置下,插入0或NULL代表生成下一個自增長值。如果用戶希望插入的值為0,而該列又是自增長的,那么這個選項就有用了。

  • STRICT_TRANS_TABLES

在該模式下,如果一個值不能插入到一個事務表中,則中斷當前的操作,對非事務表不做限制

為事務存儲引擎啟用嚴格模式, 也可能為非事務存儲引擎啟用嚴格模式。

嚴格模式控制MySQL如何處理非法或丟失的輸入值。 有幾種原因可以使一個值為非法。 例如, 數據類型錯 誤, 不適合列, 或超出范圍。 當新插入的行不包含某列的沒有顯示定義DEFAULT子句的值,則該值被丟失。 對於事務表, 當啟用STRICT_ALL_TABLES或STRICT_TRANS_TABLES模式時, 如果語句中有非法或丟失值, 則會出現錯誤。 語句被放棄並回滾。

  •  NO_ZERO_IN_DATE

在嚴格模式下,不允許日期和月份為零

  • NO_ZERO_DATE

設置該值,mysql數據庫不允許插入零日期,插入零日期會拋出錯誤而不是警告。

  • ERROR_FOR_DIVISION_BY_ZERO

在INSERT或UPDATE過程中,如果數據被零除,則產生錯誤而非警告。如果未給出該模式,那么數據被零除時MySQL返回NULL

  • NO_AUTO_CREATE_USER

禁止GRANT創建密碼為空的用戶

  • NO_ENGINE_SUBSTITUTION

如果需要的存儲引擎被禁用或未編譯,那么拋出錯誤。不設置此值時,用默認的存儲引擎替代,並拋出一個異常

  • PIPES_AS_CONCAT

將”||”視為字符串的連接操作符而非或運算符,這和Oracle數據庫是一樣的,也和字符串的拼接函數Concat相類似

舉例:

# 創建一個測試表
CREATE TABLE `employee` (
`eid` int(11) NOT NULL,
`ename` varchar(64) DEFAULT NULL,
`sex` int(11) DEFAULT NULL,
PRIMARY KEY (`eid`)
) ENGINE=InnoDB;
# 插入幾條數據
insert into employee (eid,ename,sex) values (1,'keme',18),(2,'xixi',22),(3,'yj',18),(4,'kk',18),(5,'yy',18),(6,'xx',35);

# 設置當前會話的sql_mode為如下
mysql> set @@sql_mode='STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION';

mysql> select eid,ename,count(*) from employee group by ename;
+-----+-------+----------+
| eid | ename | count(*) |
+-----+-------+----------+
|   1 | keme  |        1 |
|   4 | kk    |        1 |
|   2 | xixi  |        1 |
|   6 | xx    |        1 |
|   3 | yj    |        1 |
|   5 | yy    |        1 |
+-----+-------+----------+

# 重新設置當前的sql_mode 為如下
mysql> set @@sql_mode='ONLY_FULL_GROUP_BY';
mysql> select eid,ename,count(*) from employee group by ename;
ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'beta.employee.eid' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
mysql> select eid,ename ,count(*) from employee group by eid;
+-----+-------+----------+
| eid | ename | count(*) |
+-----+-------+----------+
|   1 | keme  |        1 |
|   2 | xixi  |        1 |
|   3 | yj    |        1 |
|   4 | kk    |        1 |
|   5 | yy    |        1 |
|   6 | xx    |        1 |
+-----+-------+----------+
6 rows in set (0.00 sec)



mysql> set @@sql_mode='STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION';
mysql> insert into employee values(7,'ke','male');
ERROR 1366 (HY000): Incorrect integer value: 'male' for column 'sex' at row 1

mysql> set @@sql_mode='ANSI';
Query OK, 0 rows affected (0.00 sec)

mysql> select @@sql_mode;
+--------------------------------------------------------------------------------+
| @@sql_mode                                                                     |
+--------------------------------------------------------------------------------+
| REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ONLY_FULL_GROUP_BY,ANSI |
+--------------------------------------------------------------------------------+

#改成ANSI模式就可以插入成功了,只不過識別成了0
mysql> insert into employee values(7,'ke','male');
Query OK, 1 row affected, 1 warning (0.01 sec)

mysql> select * from employee where eid=7;
+-----+-------+------+
| eid | ename | sex  |
+-----+-------+------+
|   7 | ke    |    0 |
+-----+-------+------+
1 row in set (0.00 sec)


mysql> set @@sql_mode='STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> select @@sql_mode;
+--------------------------------------------+
| @@sql_mode                                 |
+--------------------------------------------+
| STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION |
+--------------------------------------------+
1 row in set (0.00 sec)

mysql> insert into employee values (8,'ww',17/0);
Query OK, 1 row affected (0.00 sec)

mysql> select * from employee  where eid=8;
+-----+-------+------+
| eid | ename | sex  |
+-----+-------+------+
|   8 | ww    | NULL |
+-----+-------+------+


mysql> set @@sql_mode='STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION,ERROR_FOR_DIVISION_BY_ZERO';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> select @@sql_mode;
+-----------------------------------------------------------------------+
| @@sql_mode                                                            |
+-----------------------------------------------------------------------+
| STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+-----------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> insert into employee values (9,'ee',18/0);
ERROR 1365 (22012): Division by 0

mysql> alter table employee modify ename varchar(5);
mysql> set @@sql_mode='STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION';
mysql> insert into employee values (9,'qweradsf',11);
ERROR 1406 (22001): Data too long for column 'ename' at row 1

mysql> set @@sql_mode='ANSI';
mysql> insert into employee values (9,'qweradsf',11);
mysql> select * from employee where eid=9;
+-----+-------+------+
| eid | ename | sex  |
+-----+-------+------+
|   9 | qwera |   11 |
+-----+-------+------+


mysql> set @@sql_mode='TRADITIONAL';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> select @@sql_mode;
TRADITIONAL模式有如下值:
|STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |

  

8. 用戶的資源限制

MySQL提供了對每個用戶的資源限制管理

MAX_QUERIES_PER_HOUR : 一個用戶在一個小時內可以執行查詢的次數(基本包含 所 有 語 句 )

MAX_UPDATES_PER_HOUR:一個用戶在一個小時內可以執行修改的次數(僅包含修 改數據庫或表的語句)

MAX_CONNECTIONS_PER_HOUR:允許用戶每小時連接的次數

MAX_USER_CONNECTIONS:一個用戶可以在同一時間連MySQL實例的數量

通過執行create user/alter user設置/修改用戶的資源限制

# 創建一個用戶並設置其資源限制
CREATE USER 'keme1'@'localhost' IDENTIFIED BY
'123456' WITH MAX_QUERIES_PER_HOUR 20
MAX_UPDATES_PER_HOUR 10
MAX_CONNECTIONS_PER_HOUR 5
MAX_USER_CONNECTIONS 2;
#keme1 這個用戶 一個小時可以查詢20次, 修改10次,一個小時可以連接5次,同一時刻只允許兩個用戶

#取消某項資源限制既是把原先的值修改成0
mysql> alter user 'keme1'@'localhost' WITH MAX_CONNECTIONS_PER_HOUR 0;

# 當針對某個用戶的max_user_connections非0時, 則忽略全局系統參數max_user_connections, 反之則全局系統參數生效

  

9. 主從同步錯誤

一般主從同步錯誤首先要考慮是不是在從庫中誤操作導致的。結果發現,有人在從庫中進行了一條針對有主鍵表的 sql 語句的插入,導致主庫再插入相同 sql 的時候,主從狀態出現異常。發生主鍵沖突的報錯。

解決方法:

在確保主從數據一致性的前提下,可以在從庫進行錯誤跳過。

像從庫如果不提供什么服務的話可以在從庫中開啟 read_only 參數,禁止在從庫進行寫入操作,還有用戶必須沒有super 權限,設置read_only才會生效。

9.1 一般主從復制錯誤的解決辦法

這是正常的狀態

10.0.0.150 是主

10.0.0.151 是從

先模擬故障

# 這是本次的表結構
mysql> show create table students;
| students | CREATE TABLE `students` (
  `sid` int(11) NOT NULL,
  `sname` varchar(20) DEFAULT NULL,
  `sex` int(11) DEFAULT NULL,
  PRIMARY KEY (`sid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 
#主庫執行,是個空表
mysql> select * from students;
Empty set (0.00 sec)

#在從庫 ,給students 加1條數據: 
mysql> insert into students  values (1,'keme',0);
mysql> show slave status\G;
...
 Slave_IO_Running: Yes
 Slave_SQL_Running: Yes
...
看主從狀態是正常的
# 從庫查看students 數據
mysql> select * from students;
+-----+-------+------+
| sid | sname | sex  |
+-----+-------+------+
|   1 | keme  |    0 |
+-----+-------+------+


# 在主庫查看students 表
mysql> select * from students;
Empty set (0.00 sec)

# 插入相同主鍵的值
mysql> insert into students values (1,'keme',1);

# 查看students表
mysql> select * from students;
+-----+-------+------+
| sid | sname | sex  |
+-----+-------+------+
|   1 | keme  |    1 |
+-----+-------+------+


# 查看從庫狀態
mysql> show slave status\G;
...
Slave_IO_Running: Yes
Slave_SQL_Running: No
Last_SQL_Error: Could not execute Write_rows event on table beta.students; Duplicate entry '1' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log mysql-bin.000023, end_log_pos 11789
...
# 主從狀態不一致了,造成的原因是主鍵沖突

  

解決辦法

# 停止從庫
mysql> stop slave;

# 在從庫刪除主鍵沖突的那條語句, 把主庫執行的那條語句在從庫執行
mysql> delete from students where sid=1;
mysql> insert into students values (1,'keme',1);

# 同步跳過臨時錯誤
mysql> set global sql_slave_skip_counter = 1;
mysql> start slave;
mysql> show slave status\G;
...
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...

# 主庫再次插入數據,看看從庫是不是能夠同步
mysql> insert into students  values (2,'keme',1);

# 從庫查看
mysql> select * from students;
+-----+-------+------+
| sid | sname | sex  |
+-----+-------+------+
|   1 | keme  |    1 |
|   2 | keme  |    1 |
+-----+-------+------+
2 rows in set (0.00 sec)

# OK,同步成功了, 一般主從錯誤也就解決了

  

那這時候有問題,主從問題不一致了, 主上面插入了很多數據, 這時候該怎么解決了。

首先主從問題不一致了,你的監控預警機制了,給你發短信或者釘釘,這時候你應該盡快去修復從庫,比如就像上面跳過臨時同步錯誤,暫時讓其恢復正常同步。

其次 后期就是用pt工具:比如用pt-table-checksum 找出主從表數據不一致的, pt-table-sync進行修復從庫

 

9.2 GTID 主從復制錯誤解決辦法

現在修改我的主從模式為GTID,這是我的測試環境隨便改,

生產環境不能這樣瞎改

搭建GTID主從時,需要注意的 mysql 參數:

server_id:設置 mysql 實例的 server_id,每個實例的server_id必須不一樣

gtid_mode=on:MYSQL 實例開啟GTID 模式。

enforce_gtid_consitency=on :使用GTID模式復制時,需要開啟此參數,用來保證GTID的一致性。

log-bin=on :Msql 做主從必須開啟binlog

log-slave-updates=1 :覺得slave 從master 接收到的更新且執行完之后,執行的binlog是否記錄到slave的binlog中,建議開啟

binlog_format=row :強烈建議binlog_format使用row格式 在mysql 5.7.6 版本以后默認就是row

skip-slave-start=1 :當slave 數據庫啟動的時候,slave 不會自動開啟復制

 

主庫操作,在[mysqld] 加一下參數,我這個做過主從, 只加一部分參數

# my.cnf 中內容 
[mysqld]
gtid-mode=on
enforce-gtid-consistency=on
log-slave-updates=1

  

從庫操作

# my.cnf 中內容
[mysqld]
gtid-mode=on
enforce-gtid-consistency=on
log-slave-updates=1
skip-slave-start=1

重啟主從數據庫

 

 

在從庫 操作重新設置主從庫的復制關系

mysql> CHANGE MASTER TO
MASTER_HOST = '10.0.0.150',
MASTER_PORT = 3306,
MASTER_USER = 'repl',
MASTER_PASSWORD = '123456',
MASTER_AUTO_POSITION = 1;
mysql> start slave;

#查看主從狀態
mysql> show slave status\G;
...
 Slave_IO_Running: Yes
 Slave_SQL_Running: Yes
...

  

 

如果是在GTID模式下出現復制報錯, 則使用SQL_SLAVE_SKIP_COUNTER語句會報錯

在GTID 模式的復制情況下,如果slave 發生錯誤,則可以通過跳過該事務的方式恢復主從復制。

 

 現在人為制造slave錯誤

# 在從庫的sutdents 表插入一條數據
mysql> select * from students;
+-----+-------+------+
| sid | sname | sex  |
+-----+-------+------+
|   1 | keme  |    1 |
|   2 | keme  |    1 |
+-----+-------+------+
mysql> insert into students values (3,'keme',0);

# 在查看從庫的數據
mysql> select * from students;
+-----+-------+------+
| sid | sname | sex  |
+-----+-------+------+
|   1 | keme  |    1 |
|   2 | keme  |    1 |
|   3 | keme  |    0 |
+-----+-------+------+

# 主庫也插入主鍵為3這條數據,引發主從同步錯誤
mysql> insert into students values (3,'keme',1);

  

 

 主從報錯了:

 

 從圖中可以看出,出錯事務的binlog文件為mysql-bin.000026

開始位置(Exec_Master_Log_Pos)是154 ,結束位置是(end_log_pos ) 395,可以去主庫分析下binlog ,看一下發生沖突的事務是哪個。

可以看到接收並且執行了GTID事件 是

從庫執行了這些
5a13910d-1496-11e9-8375-000c29f859ce:1-3,
f6c31435-38dd-11e9-ac93-000c299bcbee:1-53096

收到卻沒執行的事務號:
Retrieved_Gtid_Set: f6c31435-38dd-11e9-ac93-000c299bcbee:53097

  

可以看出發現沖突的事務號是:f6c31435-38dd-11e9-ac93-000c299bcbee:53097,這時候就要確定哪一個事務發生了沖突,還可以直接從show slave status\G;結果中通過比對的方式找到沖突位置。

嚴謹起見,通過對binlog 內容分析得知沖突事務是插入了一條數據,主鍵為3。在從庫中查看這條記錄是否真的存在

mysql> select * from students where sid=3;
+-----+-------+------+
| sid | sname | sex  |
+-----+-------+------+
|   3 | keme  |    0 |
+-----+-------+------+

  

發現slave 中存在這條記錄了,這時,可以通過跳過該事務的方式來放棄該事務在slave上的執行,使slave 能夠正常運行。

基於GTID模式的復制,跳過一個事務,需要利用一個空事務來完成。

mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> set GTID_NEXT='f6c31435-38dd-11e9-ac93-000c299bcbee:53097';
Query OK, 0 rows affected (0.00 sec)

mysql> begin;commit;
Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql> set GTID_NEXT='AUTOMATIC';
Query OK, 0 rows affected (0.00 sec)

mysql> start slave;
Query OK, 0 rows affected (0.00 sec)

  

查看slave 狀態

 

 哪主從庫數據是否一致,就看3那條

# 主庫數據
mysql> select * from students where sid=3;
+-----+-------+------+
| sid | sname | sex  |
+-----+-------+------+
|   3 | keme  |    1 |
+-----+-------+------+

#從庫數據
mysql> select * from students where sid=3;
+-----+-------+------+
| sid | sname | sex  |
+-----+-------+------+
|   3 | keme  |    0 |
+-----+-------+------+

  

解決不一致數據:

1 手動修改或者插入

2 用pt用具 來修復或者檢查不一致數據

 

由於我這是我的本地環境,我只手動修改數據,再看主從狀態

mysql> update students set  sex=1 where sid=3;
Query OK, 1 row affected (0.03 sec)
Rows matched: 1  Changed: 1  Warnings: 0

 

注:不止是要主從解決錯誤,還要主從數據的一致性 

如果是生產的核心庫主從不一致,一定要查明原因,不然老是 dba 或者運維 背鍋

還有如果主從不一致性實在是太多太多不一致了,就重做數據庫吧

如果檢查的數據某幾張表不一致的情況下,可以把這幾張道出來,恢復到從庫

 

10. 數據庫總會出現中文亂碼的情況

為什么我的數據庫總會出現中文亂碼的情況。一堆中文亂碼不知道怎么回事?當向數據庫中寫入創建表,並插入中文時,會出現這種問題。此報錯會涉及數據庫字符集的問題。

10.1 解決亂碼的幾個方面

對於中文亂碼的情況,從三個方面

  • 數據終端: 就是我們連接數據庫的工具設置為utf8
  • 操作系統層面:linux 系統通過 在命令爭端查看當前編碼echo $LANG或者locale

如何修改了系統編碼了:

# centos 6.x 版本是/etc/sysconfig/i18n
修改這個文件
shell> vim /etc/sysconfig/i18n
# 這一行改為utf8
LANG=en_US.UTF-8
# 修改完,不要重啟,立即生效如下
shell> source /etc/sysconfig/i18n


# centos 7.x 版本是/etc/locale.conf 這個文件
[root@mysql-150 ~]# vim /etc/locale.conf
LANG="en_US.UTF-8"
#立即生效
[root@mysql-150 ~]# source /etc/locale.conf

  

  • 數據庫層面:

在參數文件中的[mysqld] 下,加入相應utf8字符集

# 注意數據庫的系統版本
5.6.x 和 5.7.x設置字符集參數不一樣,8.x和5.7.x設置是一樣的
#查看當前數據庫的字符集參數,查看當前字符集參數
mysql> show variables like '%character%';

# 查看數據庫支持的字符編碼,和編碼的排序規則
mysql> show character set;

# 修改sutdents表中sname 字段的字符編碼
mysql> alter table students modify sname varchar(66) character set gbk;
Query OK, 3 rows affected (0.06 sec)
Records: 3  Duplicates: 0  Warnings: 0

#看看表結構
mysql> show create table students;
...
| students | CREATE TABLE `students` (
  `sid` int(11) NOT NULL,
  `sname` varchar(66) CHARACTER SET gbk DEFAULT NULL,
  `sex` int(11) DEFAULT NULL,
  PRIMARY KEY (`sid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
...

# 查看連接級字符集和排序規則
mysql> show variables like '%collation%';
+----------------------+-----------------+
| Variable_name        | Value           |
+----------------------+-----------------+
| collation_connection | utf8_general_ci |
| collation_database   | utf8_general_ci |
| collation_server     | utf8_general_ci |
+----------------------+-----------------+

  

從上面示例可以得出:

如果修改數據庫字符集,需要從以下考

  • 列級別字符集

  • 表級別字符集

  • 庫級別字符集

  • mysql 實例字符集

10.2 怎么合理修改mysql字符集了

在/etc/my.cnf 加一下參數

vim /etc/my.cnf 
[mysqld] 
init-connect='SET NAMES utf8' 
character-set-server=utf8 
然后去數據庫操作:
mysql> set @@global.character_set_server=utf8;
Query OK, 0 rows affected (0.00 sec)

mysql> set @@global.init_connect='SET NAMES utf8';
Query OK, 0 rows affected (0.00 sec)
# 注 用戶操作的時候看看有沒有super權限,對super用戶權限 set names 不生效

  

有人說,修改完還是亂碼, 這時候就亂碼是哪個庫的字符集,哪個表的字符集,哪個字段的字符集,還有操作系統字符集,程序連接的字符集,這些都的查看。

在/etc/my.cnf中init-connect='SET NAMES utf8'是什么意思:

讓每個客戶端連接都自動設置字符集,但缺點是對擁有super權限的用戶不生效

init_connect表示服務器為每個連接的客戶端執行的字符串。字符串由一個或多個SQL語句組成。要想指定多個語句,用分號間隔開 。

 比如:

# 舉例init_connect
mysql> SET @@GLOBAL.init_connect='SET AUTOCOMMIT=0;set names
utf8';
shell> vim my.cnf
[mysqld]
init_connect='SET AUTOCOMMIT=0;set names utf8'

10.3 連接級字符集和排序規則

  • 每個數據庫客戶端連接都有自己的字符集和排序規則屬性,

    客戶端發送的語句的字符集是由character_set_client決定,

    而與服務端交互時會根據character_set_connection和collation_connection兩個參數將接收到的語句轉化。當涉及到顯示字符串的比較時,由collation_connection參數決定,

    而當比較的是字段里的字符串時則根據字段本身的排序規則決定

  • character_set_result參數決定了語句的執行結果以什么字符集返回給客戶端

  • 客戶端可以很方便的調整字符集和排序規則,比如使用SET NAMES 'charset_name' [COLLATE 'collation_name']表明后續的語句都以該字符集格式傳送給服務端,而執行結果也以此字符集格式返回。

  

set names 字符集

set names charset_name 語句相當於執行了以下三行語句:
SET character_set_client = charset_name;
SET character_set_results = charset_name;
SET character_set_connection = charset_name;

  

或者執行SET CHARACTER SET 'charset_name'命令 :此命令和set names非常類似,唯一不同是將connection的字符集設置為當前數據庫的字符集,所以相當於執行以下三行語句:

SET character_set_client = charset_name;
SET character_set_results = charset_name;
SET character_set_connection = @@character_set_database;

小結: 中文亂碼從:數據終端,操作系統,數據庫

數據庫從: 全局數據庫server字符集——>數據庫字符集——> 表字符集——> 列字符集

10.4 表情亂碼不能識別

修改存表情字段的字符集為utf8mb4  

11 can't opet file(errno:24)

有的時候,數據庫跑得好好的,突然報不能打開數據庫文件的錯誤了。

解決思路:

首先我們要先查看數據庫的 error log。然后判斷是表損壞,還是權限問題。還有可能磁盤空間不足導致的不能正常訪問表,操作系統的限制也要關注下,相關應用限制也要關注下;

#ulimit -n 查看系統的最大打開文件數
[root@mysql-150 ~]# ulimit -n
65535

查看數據庫的打開文件數

mysql> show variables like 'open_files_limit';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| open_files_limit | 5000  |
+------------------+-------+
# 根據業務實際情況修改打開文件數一般足夠用了,低版本的打開文件數,可能有點小, 注意一下

哪就是其他的問題了,可能是表的權限,也可能是表出問題,根據錯誤日志,具體分析  

處理方法

  • repair table tablename

  • chown mysql.mysql 權限 目錄

  • 清理磁盤中的垃圾數據

12. sleep 線程過多怎么解決

結果:嚴重消耗mysql服務器資源(主要是cpu, 內存),並可能導致mysql崩潰。

12.1 知道 sleep 線程過多原因

首先要知道到底是什么原因導致的 sleep 線程過多的:

  1. 程序邏輯問題,導致連接一直不釋放;

  2. mysql 參數的問題,是不是參數配置的不合理,一直不釋放連接;

  3. mysql 語句的問題,數據庫查詢不夠優化,過度耗時。

  4. 大並發情況問題,導致 sleep 情況過多;

12.2 臨時解決 sleep 線程

很多人都是重啟大法,重啟大法確實好, 能夠釋放,生產重啟對業務有影響的,不能隨便重啟的

shell腳本+cron計划任務,來kill sleep 線程,這個不靠譜啊, 你不知道 sleep 線程,里面是不是還有事務還在執行沒有提交,也是sleep 狀態,這個kill 操作有點莽夫,對生產數據數據庫還是要理智啊。

我臨時解決的辦法:

  1. 對用戶資源做限制,看看那個用戶連接的sleep線程比較多,對這個用戶連接多的做一些限制,比如一個小時可以連接多少次啊等等

  2. 修改 mysql 參數問題 ,修改wait_timeoutinteractive_timeout默認都是28800秒有,也就是8個小時以后才釋放空鏈接。

例子:

 

 

不同用戶登錄到數據庫,wait_timeout和interactive_timeout都是28800秒

修改參數,我生產環境設置的是半個小時,也就是1800秒

mysql> set global wait_timeout=1800;
mysql> set global interactive_timeout=1800;

shell> vim my.cnf
[mysqld]
wait_timeout=1800
interactive_timeout=1800

  

這樣修改完,由於已近保持的會話連接需要等到8個小時才會釋放, 所以修改了wait_timeout和interactive_timeout不會立即生效的原因,這時候就要修改連接過多的用戶資源了來釋放sleep線程了

如下:

#開啟兩個會話窗口
mysql> # 重新登錄了會話,wait_timeout和interactive會生效
mysql> show variables like 'wait_timeout';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout  | 1800  |
+---------------+-------+
1 row in set (0.00 sec)

mysql> show variables like 'interactive_timeout';
+---------------------+-------+
| Variable_name       | Value |
+---------------------+-------+
| interactive_timeout | 1800  |
+---------------------+-------+
1 row in set (0.00 sec)

#session2
mysql> #這個是其他用戶連接的mysql,這個會話一直沒有斷開,參數還是28800
mysql> show variables like 'wait_timeout';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout  | 28800 |
+---------------+-------+
1 row in set (0.01 sec)

mysql> show variables like 'interactive_timeout';
+---------------------+-------+
| Variable_name       | Value |
+---------------------+-------+
| interactive_timeout | 28800 |
+---------------------+-------+
1 row in set (0.00 sec)

 

 

13.3 怎么根本解決了

這時候就要知道 造成 sleep 線程過多的原因來解決:

  1. 程序執行完畢,應該顯式調用mysql_close

  2. 程序中根據業務訪問情況,選擇長連接還是短連接

  3. 能逐步分析系統的SQL查詢,找到查詢過慢的SQL優化

  4. 合理設置mysql參數值


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM