mysql里面integer默认宽度_MySQL中关于数据类型指定宽度之后的情况
概述
MySQL有很多種數據類型,最常用的就是int,char,varchar,這些類型在創建表的時候都可以指定該字段的寬度,方法是在類型后面加一個括號,括號中寫寬度就可以了。
但是,在指定寬度之后,有時候,我們可以看到插入的數據有一些被截斷了;有一些并沒有截斷,而是四舍五入了,甚至什么操作都沒有,原樣插入了。
下面對于每一種數據類型單獨測試:
數字型(int、tinyint...)
mysql> create table t (id int(5));
mysql> insert into t values(1234567),(123),(12345);
mysql> select * from t;
+---------+
| id |
+---------+
| 1234567 |
| 123 |
| 12345 |
+---------+
從上面的例子中可以看到,對于int而言,雖然指定了寬度,但是當插入的數據寬度大于指定的寬度時,并不會截斷。
其實對于int而言,要指定寬度,那么就必定要指定zerofill,但同樣,zerofill只是在寬度不夠的時候用0填充,但是寬度大于指定寬度時,數據仍然不會被截取。
mysql> create table t (id int(5) zerofill);
mysql> insert into t values(1234567),(123),(12345);
mysql> select * from t;
+---------+
| id |
+---------+
| 1234567 |
| 00123 |
| 12345 |
+---------+
字符串型(char、varchar)
mysql> create table t (fields_1 char(5),fields_2 varchar(5));
Query OK, 0 rows affected (0.01 sec)
mysql> insert into t values("123","123"),("12345","12345"),("1234567","1234567");
Query OK, 3 rows affected, 2 warnings (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 2
mysql> show Warnings;
+---------+------+-----------------------------------------------+
| Level | Code | Message |
+---------+------+-----------------------------------------------+
| Warning | 1265 | Data truncated for column 'fields_1' at row 3 |
| Warning | 1265 | Data truncated for column 'fields_2' at row 3 |
+---------+------+-----------------------------------------------+
2 rows in set (0.00 sec)
mysql> select fields_1,length(fields_1),fields_2,length(fields_2) from t;
+----------+------------------+----------+------------------+
| fields_1 | length(fields_1) | fields_2 | length(fields_2) |
+----------+------------------+----------+------------------+
| 123 | 3 | 123 | 3 |
| 12345 | 5 | 12345 | 5 |
| 12345 | 5 | 12345 | 5 |
+----------+------------------+----------+------------------+
可以看到,對于char和varchar,如果制定了寬度,如果要插入的字符串的寬度超過了指定的寬度,則會截取掉超出的部分。
簡單來說,varchar的可變長度,這個可變,前提是存入的字符串長度不超過定義該字段時指定的長度,如果長度超過了指定長度,即使是可變長度字符串類型,數據仍會出現截斷。
可以簡單記為:可縮不可擴。
而固定長度的char類型,在存儲效率比varchar高,但是,會存在空間浪費的情況,所以空間利用率沒有varchar高,而varchar是可變長度的,就意味著,在讀數據的時候,效率沒有char類型高,因為在讀數據的時候要判斷是否讀到結尾。
拓展1
前面已經提到,對于數值類型的字段后面的寬度來說,只有在指定zerofill的時候,后面指定的寬度才有意義,否則,既不會出現截斷,也不會出現0填充。那么,不會出現截斷,是不是說,向一個int(5)字段的插入一個值,這個值是12345678912345678912345678...(由100位數字長度),那么還能存進去嗎?
看下面示例:
mysql> create table t (id int(5) zerofill);
Query OK, 0 rows affected (0.10 sec)
mysql> insert into t values (9999999999999999999999999999999999999999999);
Query OK, 1 row affected, 2 warnings (0.00 sec)
mysql> show warnings;
+---------+------+---------------------------------------------+
| Level | Code | Message |
+---------+------+---------------------------------------------+
| Warning | 1264 | Out of range value for column 'id' at row 1 |
| Warning | 1264 | Out of range value for column 'id' at row 1 |
+---------+------+---------------------------------------------+
2 rows in set (0.00 sec)
mysql> select * from t;
+------------+
| id |
+------------+
| 4294967295 |
+------------+
1 row in set (0.00 sec)
可以從警告信息和執行結果中看出,當嘗試向指定寬度字段插入一個很大的數據,大到遠超該數據類型的上限,執行雖然會出現警告,但是,數據確實插入了,只不過存儲的數據不是插入的數據,而是存了一個該類型的最大值。
所以可以得出結論:對一個數字類型的字段而言,其數據類型已經限定了它的數據范圍,當嘗試插入一個超過數據范圍的值時,會觸發警告,同時,存入該數據類型的最大值。
拓展2
前面也提到了字符串(char和varchar)后面指定的寬度,這個寬度就不像數字類型的寬度了,因為,如果是字符串類型,那么,一旦超過字符串后面指定的寬度,那么一定會出現截斷。
這里有個問題,字符串后面指定的寬度,比如char(5),varchar(5),這個5是指5個字符,還是指5個字節呢,或者說是5個bit(位)呢?
前面的示例中,很顯然看出,這個5不可能是bit(位),畢竟一個字節就有8位,在測試中,一個字符都插不進去。
那么,要么是5個字符,或者5個字節。可能你會疑惑,5個字符和5個字節有什么區別嗎?abc,是3個字符,同時也是3個字節,何必去區分呢?
那你想一下,咱們的漢字,一個漢字,經過不同的編碼(GBK,GB2312,lantin1,UTF-8,UTF-8mb4)之后,所占的字節數是不一定相同的呀。
mysql> create table t (field char(5));
Query OK, 0 rows affected (0.40 sec)
mysql> show create table t\G
*************************** 1. row ***************************
Table: t
Create Table: CREATE TABLE `t` (
`field` char(5) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
mysql> insert into t values ('abcde');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t values ('中國你好啊');
Query OK, 1 row affected, 2 warnings (0.00 sec)
mysql> show warnings;
+---------+------+-----------------------------------------------------------------------------------+
| Level | Code | Message |
+---------+------+-----------------------------------------------------------------------------------+
| Warning | 1300 | Invalid utf8 character string: 'D6D0B9' |
| Warning | 1366 | Incorrect string value: '\xD6\xD0\xB9\xFA\xC4\xE3...' for column 'field' at row 1 |
+---------+------+-----------------------------------------------------------------------------------+
2 rows in set (0.00 sec)
從上面的實例,很明顯可以看出答案,char(5)后面的5,是指的5字節,而不是5個字符。
可以查看一下,存入的內容是什么:
mysql> select * from t;
+-------+
| field |
+-------+
| abcde |
| ????? |
+-------+
2 rows in set (0.03 sec)
mysql> set names utf8;
Query OK, 0 rows affected (0.02 sec)
mysql> select * from t;
+-------+
| field |
+-------+
| abcde |
| ????? |
+-------+
2 rows in set (0.00 sec)
可以看出,后面雖然插入的“中國你好啊”,但是存的時候,已經出現亂碼了,即使強制指定字符集,也是顯示亂碼。
咱們一般使用的都會utf8或者utf8mb4,可以在創建表格的時候,指定default charset=utf8。
拓展3
如果一個漢字使用某種編碼方式(比如utf8),在存儲的時候占3字節,那么兩個漢字,就需要6個字節來存。
那么,如果char(5)類型的字段,能存入“中國”兩個字嗎?中國兩個字編碼之后是6字節。
首先解決一個問題:
mysql> create table t ( field char(5)) default charset=utf8;
Query OK, 0 rows affected (0.11 sec)
mysql> insert into t values ('abcde');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t values ('中');
Query OK, 1 row affected, 2 warnings (0.00 sec)
mysql> show warnings;
+---------+------+----------------------------------------------------------------+
| Level | Code | Message |
+---------+------+----------------------------------------------------------------+
| Warning | 1300 | Invalid utf8 character string: 'D6D0' |
| Warning | 1366 | Incorrect string value: '\xD6\xD0' for column 'field' at row 1 |
+---------+------+----------------------------------------------------------------+
2 rows in set (0.00 sec)
mysql> select * from t;
+-------+
| field |
+-------+
| abcde |
| |
+-------+
2 rows in set (0.00 sec)
mysql> set names utf8;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t;
+-------+
| field |
+-------+
| abcde |
| |
+-------+
2 rows in set (0.00 sec)
可以看到,即使單個漢字“中”編碼之后3字節(未超過5字節范圍,仍舊未存入),這時可以看一下數據庫的字符集:
mysql> show variables like '%char%';
+--------------------------+-----------------------------------+
| Variable_name | Value |
+--------------------------+-----------------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | E:\phpStudy\MySQL\share\charsets\ |
+--------------------------+-----------------------------------+
8 rows in set (0.00 sec)
可以看到,character_set_database設定的還是latin1字符集編碼,可以使用下面的命令修改:
set character_set_database='utf8';
接下來,測試過程中,即使插入單獨的一個漢字,也會出現警告,并且查看插入的值,只出現一個?或者一些亂碼,甚至沒有值(空的)。
我嘗試在php中執行插入和查看操作:
$mysqli = new Mysqli();
$mysqli->connect("localhost","root","root","test");
$mysqli->set_charset("utf8");
$mysqli->query("truncate table t");
$mysqli->query("insert into t values ('abcde')");
$mysqli->query("insert into t values ('你')");
$mysqli->query("insert into t values ('你好')");
$sql = "select * from t";
$mysqli_result = $mysqli->query($sql);
$res = $mysqli_result->fetch_all();//一次性去的所有數據
print_r($res);
執行之后,結果如下:
λ php index.php
Array
(
[0] => Array
(
[0] => abcde
)
[1] => Array
(
[0] => ?
)
[2] => Array
(
[0] => ???
)
)
至于為什么會這樣,現在還沒找到問題根源。之前好像也沒遇到過這種情況呀,等有時間在其他機器上試一下。
總結
以上是生活随笔為你收集整理的mysql里面integer默认宽度_MySQL中关于数据类型指定宽度之后的情况的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 幽灵交易策略_源码 | 幽灵交易者策略
- 下一篇: mysql反应慢_MySQL反应慢排查思