float、double精度可能丟失,decimal精度不會丟失,所以建議decimal來存儲金額值。
在mysql中,我們用【小數數據類型(總長度,小數點長度)】來表示小數的總長度和小數點后面的長度。decimal(m,n)。n就是小數點后面的 數字個數。float(m,n)、double(m,n)含義差不多,都是定義長度和精度的。
下面看實操演示
-- total_price精度為小數點后六位
CREATE TABLE `order` ( `id` bigint(11) NOT NULL, `total_price` float(10,6) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- insert
INSERT INTO `co_job`.`order`(`total_price`) VALUES (32.214);
-- query
SELECT * FROM `order` WHERE `id` = 1;

第一種情況: 存入小數精度不夠6位
那么mysql會盡可能以近似的值存儲,以保證精度。這里會出現精度丟失
第二種情況: 存入小數精度剛好6位
INSERT INTO `order`(`total_price`) VALUES (32.214412);
SELECT * FROM `order` WHERE `id` = 2;

仍然發生了精度丟失。
在查閱資料可知,單精度類型float和雙精度類型double在計算機中存儲的時候,由於計算機只能存儲二進制,所以浮點型數據在存儲的時候,必須轉化成二進制。在計算機中,float型數據的存儲格式為
比如8.25用二進制表示可表示為1000.01,轉成指數的形式1.00001*2^3,在計算機中
我們知道對於float類型的數據,只分配了32位的存儲空間,對於double類型值分配了64位,但是並不是所有的實數都能轉成32位或者64位的二進制形式,如果超過了,就會出現截斷,這就是誤差的來源。
比如131072.32轉成二進制后的數據為:100000000000000000.0101000111101011100001010001111010111000010100011111… 這是一個無窮數,對於float類型,只能截取前32位進行存儲,對於double只能截取前64位進行存儲。所以 131072.32保存為float類型是存儲形式為:01001000000000000000000000010100; 131072.32保存為double類型的格式為:0100000100000000000000000000001010001111010111000010100011110101
針對float情況,至少我們可以得出結論:
1.如果一個float型數據轉成二進制后的第32位之后都是0,那么數據是准的
2.如果一個float型數據轉成二進制后的第32位之后不全為0,則數據就會存在誤差
第三種情況:存入小數精度大於6位
這種情況不必多說,一定會出現精度丟失。
參考資料:https://cloud.tencent.com/developer/article/1866266