天天看點

MySQL中Decimal類型和Float Double的差別 & BigDecimal與Double使用場景

MySQL中存在float,double等非标準資料類型,也有decimal這種标準資料類型。

其差別在于,float,double等非标準類型,在DB中儲存的是近似值,而Decimal則以字元串的形式儲存數值。

float,double類型是可以存浮點數(即小數類型),但是float有個壞處,當你給定的資料是整數的時候,那麼它就以整數給你處理。這樣我們在存取貨币值的時候自然遇到問題,我的default值為:0.00而實際存儲是0,同樣我存取貨币為12.00,實際存儲是12。

幸好mysql提供了兩個資料類型:decimal,這種資料類型可以輕松解決上面的問題:decimal類型被 MySQL 以同樣的類型實作,這在 SQL92 标準中是允許的。他們用于儲存對準确精度有重要要求的值,例如與金錢有關的資料。

資料定義

float(M,S) M為全長,S為小數點後長度。

資料庫類型和Java類型之間的關系:              

    DBC Type                            Java Type 

    CHAR                                     String 

    VARCHAR                              String 

    LONGVARCHAR                    String 

    NUMERIC                        java.math.BigDecimal 

    DECIMAL                         java.math.BigDecimal 

    BIT                                        boolean

    BOOLEAN                            boolean 

    TINYINT                                  byte 

    SMALLINT                              short 

    INTEGER                                int 

    BIGINT                                    long 

    REAL                                      float 

    FLOAT                                   double 

    DOUBLE                               double 

    BINARY                                 byte[] 

    VARBINARY                          byte[] 

    LONGVARBINARY                byte[] 

    DATE                                  java.sql.Date 

    TIME                                   java.sql.Time 

    TIMESTAMP                       java.sql.Timestamp 

    CLOB                                     Clob 

    BLOB                                     Blob 

    ARRAY                                  Array 

    DISTINCT                           mapping of underlying type 

    STRUCT                                Struct 

    REF                                        Ref  

項目中BigDecimal與Double使用場景金額要用BigDecimal

金額計算不能用doube!!!!

金額計算必須用BigDecimal,下面對比一下用double 跟BigDecimal的差別。先看一個小例子:

請看題:

MySQL中Decimal類型和Float Double的差別 & BigDecimal與Double使用場景

示例1

問, 結果是多少? 0.01?

No! 結果是0.009999999999999998!

為什麼會這樣呢? 因為float和double都是浮點數, 都有取值範圍, 都有精度範圍. 浮點數與通常使用的小數不同, 使用中, 往往難以确定.

常見的問題是定義了一個浮點數, 經過一系列的計算, 它本來應該等于某個确定值, 但實際上并不是!

double相減會轉換成二進制,因double有效位數為 16位這就會出現存儲小數位數不夠的情況,這種情況下就會出現誤差,解決方法就是使用BigDecimal,它的有效長度足夠長可存儲小數位數。

是以可代替double來進行加減乘除, 金額必須是完全精确的計算, 故不能使用double或者float, 而應該采用java.math.BigDecimal.

加減乘除

兩個BigDecimal值應該怎樣進行加減乘除呢? +, -, *, / 這樣寫嗎? 不!

請看示例:

MySQL中Decimal類型和Float Double的差別 & BigDecimal與Double使用場景

加減乘除使用了英文的加減乘除, 即add, substract, multiply和divide

大小比較

兩個BigDecimal值怎麼比較大小呢? 能用>或者<嗎? 也不可以!

MySQL中Decimal類型和Float Double的差別 & BigDecimal與Double使用場景

兩個BigDecimal值比較使用compareTo方法, 比較結果有-1, 0, 1, 分别表示小于, 等于, 大于; 對于0, 可以使用BigDecimal.ZERO表示!

四舍五入

MySQL中Decimal類型和Float Double的差別 & BigDecimal與Double使用場景

簡化BigDecimal計算的小工具類

如果我們要做一個加法運算,需要先将兩個浮點數轉為String,然後夠造成BigDecimal,在其中一個上調用add方法,傳入另一個作為參數,然後把運算的結果(BigDecimal)再轉換為浮點數。

你能夠忍受這麼煩瑣的過程嗎?

網上提供的工具類Arith來簡化操作。它提供以下靜态方法,包括加減乘除和四舍五入:   

public   static   double   add(double   v1,double   v2)   

public   static   double   sub(double   v1,double   v2)   

public   static   double   mul(double   v1,double   v2)   

public   static   double   div(double   v1,double   v2)   

public   static   double   div(double   v1,double   v2,int   scale)   

public   static   double   round(double   v,int   scale)  

+ View Code

  

定點數和浮點數的差別

在計算機系統的發展過程中,曾經提出過多種方法表達實數。典型的比如相對于浮點數的定點數(Fixed Point Number)。在這種表達方式中,小數點固定的位于實數所有數字中間的某個位置。

貨币的表達就可以使用這種方式,比如 99.00 或者 00.99 可以用于表達具有四位精度(Precision),小數點後有兩位的貨币值。由于小數點位置固定,是以可以直接用四位數值來表達相應的數值。

SQL 中的 NUMBER 資料類型就是利用定點數來定義的。還有一種提議的表達方式為有理數表達方式,即用兩個整數的比值來表達實數。

定點數表達法的缺點在于其形式過于僵硬,固定的小數點位置決定了固定位數的整數部分和小數部分,不利于同時表達特别大的數或者特别小的數。

最終,絕大多數現代的計算機系統采納了所謂的浮點數表達方式。這種表達方式利用科學計數法來表達實數,即用一個尾數(Mantissa ),一個基數(Base),一個指數(Exponent)以及一個表示正負的符号來表達實數。

比如 123.45 用十進制科學計數法可以表達為 1.2345 × 102 ,其中 1.2345 為尾數,10 為基數,2 為指數。浮點數利用指數達到了浮動小數點的效果,進而可以靈活地表達更大範圍的實數。

在MySQL中使用浮點數類型和定點數類型來表示小數。浮點數類型包括單精度浮點數(FLOAT型)和雙精度浮點數(DOUBLE型)。定點數類型就是DECIMAL型。MySQL的浮點數類型和定點數類型如下表所示:

<col>

類型名稱

位元組數

負數的取值範圍

非負數的取值範圍

FLOAT

4

-3.402823466E+38~

-1.175494351E-38

0和1.175494351E-38~

3.402823466E+38

DOUBLE

8

-1.7976931348623157E+308~

-2.2250738585072014E-308

0和2.2250738585072014E-308~

1.7976931348623157E+308

DECIMAL(M,D)或DEC(M,D)

M+2

同DOUBLE型

從上表中可以看出,DECIMAL型的取值範圍與DOUBLE相同。但是,DECIMAL的有效取值範圍由M和D決定,而且DECIMAL型的位元組數是M+2,也就是說,定點數的存儲空間是根據其精度決定的。

 MySQL

 BigDecimal在進行入庫時, 資料庫選擇decimal類型, 長度可以自定義, 如18; 小數點我們項目中用的是2, 保留2位小數. 此外還要注意的就是預設值, 一定寫成0.00, 不要用預設的NULL, 否則在進行加減排序等操作時, 會帶來轉換的麻煩!

MySQL ​<code>​DECIMAL​</code>​資料類型用于在資料庫中存儲精确的數值。我們經常将​<code>​DECIMAL​</code>​資料類型用于保留準确精确度的列,例如會計系統中的貨币資料。

要定義資料類型為​<code>​DECIMAL​</code>​的列,請使用以下文法:

1

​<code>​column_name  ​</code>​​<code>​DECIMAL​</code>​​<code>​(P,D);​</code>​

在上面的文法中:

​<code>​P​</code>​是表示有效數字數的精度。 ​<code>​P​</code>​範圍為​<code>​1〜65​</code>​。

​<code>​D​</code>​是表示小數點後的位數。 ​<code>​D​</code>​的範圍是​<code>​0​</code>​~​<code>​30​</code>​。MySQL要求​<code>​D​</code>​小于或等于(​<code>​&lt;=​</code>​)​<code>​P​</code>​。

​<code>​DECIMAL(P,D)​</code>​表示列可以存儲​<code>​D​</code>​位小數的​<code>​P​</code>​位數。十進制列的實際範圍取決于精度和刻度。

與INT資料類型一樣,​<code>​DECIMAL​</code>​類型也具有​<code>​UNSIGNED​</code>​和​<code>​ZEROFILL​</code>​屬性。 如果使用​<code>​UNSIGNED​</code>​屬性,則​<code>​DECIMAL UNSIGNED​</code>​的列将不接受負值。

如果使用​<code>​ZEROFILL​</code>​,MySQL将把顯示值填充到​<code>​0​</code>​以顯示由列定義指定的寬度。 另外,如果我們對​<code>​DECIMAL​</code>​列使用​<code>​ZERO FILL​</code>​,MySQL将自動将​<code>​UNSIGNED​</code>​屬性添加到列。

以下示例使用​<code>​DECIMAL​</code>​資料類型定義的一個叫作​<code>​amount​</code>​的列。

​<code>​amount ​</code>​​<code>​DECIMAL​</code>​​<code>​(6,2);​</code>​

在此示例中,​<code>​amount​</code>​列最多可以存儲​<code>​6​</code>​位數字,小數位數為​<code>​2​</code>​位; 是以,​<code>​amount​</code>​列的範圍是從​<code>​-9999.99​</code>​到​<code>​9999.99​</code>​。