問題來源:java
前幾天用戶向我反映了一個問題,有一個金額字段當輸入到達百萬級時,個位數的精度會丟失,即1000001會顯示爲100W,而後我就開始查找問題所在。mysql
背景:sql
首先,實體類該字段爲float類型,mysql類型也爲float,而後當我在後臺保存數據時:數據庫
假設金額nowPrice = 1008622,java輸出爲:1008620,而mysql顯示爲:數組
顯然是由於科學計數法把個位數的精度丟失了,從而致使數據出錯。
oracle
問題分析過程:測試
一開始我認爲是java問題,由於float、double類型當位數過多時會自動轉化爲科學計數法,可能在轉換的過程當中精度丟失了,從而致使數據庫的數據出錯。spa
爲了驗證以上說法,我使用sql查詢語句來測試,結果:ci
即便用1008622做爲條件能夠正確查詢到記錄,而使用1008620是不能查詢到記錄的,所以我認爲數據庫的真實數據是正確的,但顯示則使用丟失了精度的科學計數法。字符串
而後我直接使用mysql驅動鏈接數據庫並查詢結果,發現ResultSet rs.getString("nowPrice") = 1.00862e+06,rs.getFloat("nowPrice") = 1008620.0,可見mysql是把丟失了精度的科學計數法直接返回給應用。
至此能夠肯定是mysql的問題了,因而我查詢了相關資料並請教公司DBA,原來float、double是屬於非標準類型,他們在mysql中保存的是近似值,會致使精度問題。
以後我作了更多測試,包括添加小數點數值。當添加了小數點以後,基本上沒法使用該字段做精確的條件查詢出來了。
PS:可使用此方法查出來:select * from tt_price where price = (select price from tt_price);
總結float類型的問題:1.數值達到百萬級別時真實數值與顯示數值不一致;2.返回給應用的數值不是真實數值;3.小數點位數過多時會進行四捨五入,致使查詢、更新操做出現異常狀況。
相似的double類型一樣存在以上的問題,只不過double是雙精度,須要更高位數時才能出現這種問題。
結論:
所以,在比較敏感的字段上如金額等字段,建議使用:mysql使用decimal類型,oracle使用Number類型。Decimal是以字符串的形式保存數值,Number則是變長阿拉伯數字數組。二者都可以指定總位數和小數位,另外精度和小數位不會影響數據如何存儲,只會影響容許哪些數值及數值如何舍入。
續篇:
後來通過測試,mysql的float和double也能夠指定總位數和小數位,顯式地指定位數和小數位後效果與decimal無差,不會存上真實數值與顯示數值不一致,所以float基本能知足咱們的平常需求了,只是必需要指定位數而已。