這十個MySQL經典錯誤,99%的程序員必定遇到過!你呢?


原文:http://blog.51cto.com/sumongo...前端

今天就給你們列舉 MySQL 數據庫中,最經典的十大錯誤案例,並附有處理問題的解決思路和方法,但願能給剛入行,或數據庫愛好者一些幫助,從此再遇到任何報錯,咱們均可以很淡定地去處理。學習任何一門技術的同時,其實就是自我修煉的過程。沉下心,嘗試去擁抱數據的世界!java

Top  1:Too many connections(鏈接數過多,致使鏈接不上數據庫,業務沒法正常進行)

問題還原
mysql> show variables like '%max_connection%';  
| Variable_name   | Value |  
| max_connections | 151   |  

mysql> set global max_connections=1;Query OK, 0  rows affected (0.00 sec)  

[root@node4 ~]# mysql -uzs -p123456 -h 192.168.56.132  
ERROR 1040 (00000): Too many connections
解決問題的思路:
  • 一、首先先要考慮在咱們 MySQL 數據庫參數文件裏面,對應的max_connections 這個參數值是否是設置的過小了,致使客戶端鏈接數超過了數據庫所承受的最大值。
    ● 該值默認大小是151,咱們能夠根據實際狀況進行調整。
    ● 對應解決辦法:set global max_connections=500
    但這樣調整會有隱患,由於咱們沒法確認數據庫是否能夠承擔這麼大的鏈接壓力,就比如原來一我的只能吃一個饅頭,但如今卻非要讓他吃 10 個,他確定接受不了。反應到服務器上面,就有可能會出現宕機的可能。
    因此這又反應出了,咱們在新上線一個業務系統的時候,要作好壓力測試。保證後期對數據庫進行優化調整。
  • 二、其次能夠限制Innodb 的併發處理數量,若是 innodb_thread_concurrency = 0(這種表明不受限制) 能夠先改爲 16或是64 看服務器壓力。若是很是大,能夠先改的小一點讓服務器的壓力下來以後,而後再慢慢增大,根據本身的業務而定。我的建議能夠先調整爲 16 便可。
    MySQL 隨着鏈接數的增長性能是會降低的,可讓開發配合設置 thread pool,鏈接複用。在MySQL商業版中加入了thread pool這項功能,另外對於有的監控程序會讀取 information_schema 下面的表,能夠考慮關閉下面的參數
innodb_stats_on_metadata=0set global innodb_stats_on_metadata=0

Top 2:(主從複製報錯類型)

Last_SQL_Errno: 1062  (從庫與主庫數據衝突)
Last_Errno: 1062   
Last_Error: Could not execute Write_rows event on table test.t;    
Duplicate entry '4' for key 'PRIMARY',    
Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY;    
the event's master log mysql-bin.000014, end_log_pos 1505

針對這個報錯,咱們首先要考慮是否是在從庫中誤操做致使的。結果發現,咱們在從庫中進行了一條針對有主鍵表的 sql 語句的插入,致使主庫再插入相同 sql 的時候,主從狀態出現異常。發生主鍵衝突的報錯。node

解決方法:

在確保主從數據一致性的前提下,能夠在從庫進行錯誤跳過。通常使用 percona-toolkit 中的 pt-slave-restart 進行。
在從庫完成以下操做mysql

[root@zs bin]# ./pt-slave-restart -uroot -proot123
2017-07-20T14:05:30 p=...,u=root node4-relay-bin.000002   1506 1062
  • 以後最好在從庫中開啓 read_only 參數,禁止在從庫進行寫入操做
Last_IO_Errno: 1593(server-id衝突)
Last_IO_Error:   
 Fatal error: The slave I/O thread stops because master and slave have equal MySQL server ids;   
 these ids must be different for replication to work   (or the --replicate-same-server-id option must be used on slave but this   
 does not always make sense; please check the manual before using it)
 #這個報錯出現以後,就看一目瞭然看到兩臺機器的 server-id 是同樣的。

在搭建主從複製的過程當中,咱們要確保兩臺機器的 server-id 是惟一的。這裏再強調一下 server-id 的命名規則(服務器 ip 地址的最後一位+本 MySQL 服務的端口號)linux

解決方法:

在主從兩臺機器上設置不一樣的 server-id。sql

Last_SQL_Errno: 1032(從庫少數據,主庫更新的時候,從庫報錯)
Last_SQL_Error:Could not execute Update_rows event on table test.t; Can't find record in 't', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log mysql-bin.000014, end_log_pos 1708
解決問題的辦法:

根據報錯信息,咱們能夠獲取到報錯日誌和position號,而後就能找到主庫執行的哪條sql,致使的主從報錯。
在主庫執行:mongodb

/usr/local/mysql/bin/mysqlbinlog --no-defaults -v -v --base64-output=decode-rows /data/mysql/mysql-bin.000014 |grep -A 10 1708 > 1.logcat 1.log
#170720 14:20:15 server id 3  end_log_pos 1708 CRC32 0x97b6bdec     Update_rows: table id 113 flags: STMT_END_F
### UPDATE `test`.`t`
### WHERE
###   @1=4 /* INT meta=0 nullable=0 is_null=0 */
###   @2='dd' /* VARSTRING(60) meta=60 nullable=1 is_null=0 */
### SET
###   @1=4 /* INT meta=0 nullable=0 is_null=0 */
###   @2='ddd' /* VARSTRING(60) meta=60 nullable=1 is_null=0 */
# at 1708
#170720 14:20:15 server id 3  end_log_pos 1739 CRC32 0xecaf1922     Xid = 654
COMMIT/*!*/;
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

獲取到 sql 語句以後,就能夠在從庫反向執行 sql 語句。把從庫缺乏的 sql 語句補全,解決報錯信息。
在從庫依次執行:數據庫

mysql> insert into t (b) values ('ddd');
Query OK, 1 row affected (0.01 sec)
mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)
mysql> exit
Bye
[root@node4 bin]# ./pt-slave-restart -uroot -proot123
2017-07-20T14:31:37 p=...,u=root node4-relay-bin.000005         283 1032
Top 3:MySQL安裝過程當中的報錯
[root@zs data]# /usr/local/mysql/bin/mysqld_safe --defaults-file=/etc/my.cnf &[1] 3758
[root@zs data]# 170720 14:41:24 mysqld_safe Logging to '/data/mysql/error.log'.
170720 14:41:24 mysqld_safe Starting mysqld daemon with databases from /data/mysql170720 
14:41:25 mysqld_safe mysqld from pid file /data/mysql/node4.pid ended
170720 14:41:24 mysqld_safe Starting mysqld daemon with databases from /data/mysql2017-07-20 
14:41:25 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. 
Please use --explicit_defaults_for_timestamp server option (see documentation for more details)./usr/local/mysql/bin/mysqld: 
File '/data/mysql/mysql-bin.index' not found (Errcode: 13 - Permission denied)
2017-07-20 14:41:25 4388 [ERROR] Aborting
解決思路:

遇到這樣的報錯信息,咱們要學會時時去關注錯誤日誌 error log 裏面的內容。看見了關鍵的報錯點Permission denied。證實當前 MySQL 數據庫的數據目錄沒有權限。vim

解決方法:
[root@zs data]# chown mysql:mysql -R mysql
[root@zs data]# /usr/local/mysql/bin/mysqld_safe --defaults-file=/etc/my.cnf &
[1] 4402
[root@zs data]# 170720 14:45:56 mysqld_safe Logging to '/data/mysql/error.log'.
170720 14:45:56 mysqld_safe Starting mysqld daemon with databases from /data/mysql
#啓動成功。

如何避免這類問題,我的建議在安裝MySQL初始化的時候,必定加上--user=mysql,這樣就能夠避免權限問題。服務器

./mysql_install_db --basedir=/usr/local/mysql/ --datadir=/data/mysql/ --defaults-file=/etc/my.cnf --user=mysql
Top 4:數據庫密碼忘記的問題
[root@zs ~]# mysql -uroot -p
Enter password: 
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
[root@zs ~]# mysql -uroot -p
Enter password: 
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
#咱們有可能剛剛接手別人的 MySQL 數據庫,並且沒有完善的交接文檔。root 密碼能夠丟失或者忘記了。
解決思路:

目前是進入不了數據庫的狀況,因此咱們要考慮是否是能夠跳過權限。由於在數據庫中,mysql數據庫中user表記錄着咱們用戶的信息。

解決方法:

啓動 MySQL 數據庫的過程當中,能夠這樣執行:

/usr/local/mysql/bin/mysqld_safe --defaults-file=/etc/my.cnf  --skip-grant-tables &
這樣啓動,就能夠不用輸入密碼,直接進入 mysql 數據庫了。而後在修改你本身想要改的root密碼便可。
update mysql.user set password=password('root123') where user='root';

Top 5:truncate 刪除數據,致使自動清空自增ID,前端返回報錯 not found。

這個問題的出現,就要考慮下truncate 和 delete 的區別了。

看下實驗演練:
#首先先建立一張表;  
CREATE TABLE `t` (  
`a` int(11) NOT NULL AUTO_INCREMENT,  
`b` varchar(20) DEFAULT NULL,  
 PRIMARY KEY (`a`),  
KEY `b` (`b`)  
) ENGINE=InnoDB AUTO_INCREMENT=300 DEFAULT CHARSET=utf8  
#插入三條數據:  
mysql> insert into t (b) values ('aa');  
Query OK, 1 row affected (0.00 sec)  
mysql> insert into t (b) values ('bb');  
Query OK, 1 row affected (0.00 sec)  
mysql> insert into t (b) values ('cc');  
Query OK, 1 row affected (0.00 sec)  
mysql> select * from t;  
+-----+------+  
| a   | b    |  
+-----+------+  
|  300  | aa |  
| 301   |bb  |  
|  302  |cc  |  
+-----+------+  
3 rows in set (0.00 sec)  
#先用 delete 進行刪除全表信息,再插入新值。

結果發現truncate把自增初始值重置了,自增屬性從1開始記錄了。當前端用主鍵id進行查詢時,就會報沒有這條數據的錯誤。
我的建議不要使用truncate對錶進行刪除操做,雖然能夠回收表空間,可是會涉及自增屬性問題。這些坑,咱們不要輕易鑽進去。

Top 6:阿里雲 MySQL 的配置文件中,須要注意一個參數設置就是:
lower_case_table_names = 0;默認狀況
lower_case_table_names = 1;是不區分大小寫 . 若是報你小寫的表名找不到, 那你就把遠端數據庫的表名改爲小寫 , 反之亦然 . 注意 Mybatis 的 Mapper 文件的全部表名也要相應修改
Top 7:數據庫總會出現中文亂碼的狀況
解決思路:

對於中文亂碼的狀況,記住老師告訴你的三個統一就能夠。還要知道在目前的mysql數據庫中字符集編碼都是默認的UTF8

處理辦法:
一、數據終端,也就是咱們鏈接數據庫的工具設置爲 utf8
二、操做系統層面;能夠經過 cat /etc/sysconfig/i18n 查看;也要設置爲 utf8
三、數據庫層面;在參數文件中的 mysqld 下,加入 character-set-server=utf8。

Emoji 表情符號錄入 mysql 數據庫中報錯。

Caused by: java.sql.SQLException: Incorrect string value: '\xF0\x9F\x98\x97\xF0\x9F...' for column 'CONTENT' at row 1
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1074)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4096)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4028)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2490)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2651)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2734)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2155)
at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:1379)

解決思路:針對表情插入的問題,必定仍是字符集的問題。
處理方法:咱們能夠直接在參數文件中,加入

vim /etc/my.cnf
[mysqld]
init-connect='SET NAMES utf8mb4'
character-set-server=utf8mb4
注:utf8mb4 是 utf8 的超集。
Top 8:使用 binlog_format=statement 這種格式,跨庫操做,致使從庫丟失數據,用戶訪問致使出現錯誤數據信息。
#當前數據庫二進制日誌的格式爲:
binlog_format=statement
在主庫設置binlog-do-db=mydb1(只同步mydb1這一個庫)
在主庫執行use mydb2;
insert into mydb1.t1 values ('bb');
這條語句不會同步到從庫。可是這樣操做就能夠;
use mydb1;
insert into mydb1.t1 values ('bb');
由於這是在同一個庫中完成的操做。
#在生產環境中建議使用binlog的格式爲row,並且慎用binlog-do-db參數。
Top 9:MySQL 數據庫鏈接超時的報錯 
org.hibernate.util.JDBCExceptionReporter - SQL Error:0, SQLState: 08S01
org.hibernate.util.JDBCExceptionReporter - The last packet successfully received from the server was43200 milliseconds ago.The last packet sent successfully to the server was 43200 milliseconds ago, which is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection 'autoReconnect=true' to avoid this problem.
org.hibernate.event.def.AbstractFlushingEventListener - Could not synchronize database state with session
org.hibernate.exception.JDBCConnectionException: Could not execute JDBC batch update
com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Connection.close() has already been called. Invalid operation in this state.
org.hibernate.util.JDBCExceptionReporter - SQL Error:0, SQLState: 08003
org.hibernate.util.JDBCExceptionReporter - No operations allowed after connection closed. Connection was implicitly closed due to underlying exception/error: 
** BEGIN NESTED EXCEPTION **
#大多數作 DBA 的同窗,可能都會被開發人員告知,大家的數據庫報了這個錯誤了。趕忙看看是哪裏的問題。

這個問題是由兩個參數影響的,wait_timeout 和 interactive_timeout。數據默認的配置時間是28800(8小時)意味着,超過這個時間以後,MySQL 數據庫爲了節省資源,就會在數據庫端斷開這個鏈接,Mysql服務器端將其斷開了,可是咱們的程序再次使用這個鏈接時沒有作任何判斷,因此就掛了。

解決思路:

先要了解這兩個參數的特性;這兩個參數必須同時設置,並且必需要保證值一致才能夠。
咱們能夠適當加大這個值,8小時太長了,不適用於生產環境。由於一個鏈接長時間不工做,還佔用咱們的鏈接數,會消耗咱們的系統資源。

解決方法:

能夠適當在程序中作判斷;強烈建議在操做結束時更改應用程序邏輯以正確關閉鏈接;而後設置一個比較合理的timeout的值(根據業務狀況來判斷)

Top 10 :can't open file (errno:24)

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

解決思路:

首先咱們要先查看數據庫的error log。而後判斷是表損壞,仍是權限問題。還有可能磁盤空間不足致使的不能正常訪問表;操做系統的限制也要關注下;用 perror 工具查看具體錯誤!

linux:/usr/local/mysql/bin # ./perror 24
OS error code  24:  Too many open files

超出最大打開文件數限制!ulimit -n查看系統的最大打開文件數是65535,不可能超出!那必然是數據庫的最大打開文件數超出限制!
在 MySQL 裏查看最大打開文件數限制命令:show variables like 'open_files_limit';
發現該數值太小,改成2048,重啓 MySQL,應用正常

處理方法:
repair table ;
chown mysql權限
#清理磁盤中的垃圾數據

從此還會繼續總結 MySQL 中的各類報錯處理思路與方法,但願跟各位老鐵們,同窗們一塊兒努力。多溝通多交流!

看到這裏的各位老司機們,把此文轉發出去吧,讓更多的人成爲老司機。

相關文章
相關標籤/搜索