MySQL 常見錯誤

1. Too many connections

ERROR 1040 (HY000): Too many connections mysql

致使結果:linux

鏈接數過多,致使鏈接不上數據庫,業務沒法正常進行sql

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

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

  

解決問題思路:數據庫

一、首先先要考慮在咱們 MySQL 數據庫參數文件裏面,對應的 max_connections 這個參數值是否是設置的過小了,致使客戶端鏈接數超過了數據庫所承受的最大值。vim

  • 該值默認大小是 151,能夠根據實際狀況進行調整。centos

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

這樣調整會有隱患,由於咱們沒法確認數據庫是否能夠承擔這麼大的鏈接壓力,就比如原來一我的只能吃一斤牛肉,但如今卻非要讓他吃 10斤牛肉,他確定接受不了。反應到服務器上面,就有可能會出現宕機的可能。服務器

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

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參數值

相關文章
相關標籤/搜索