在我們日常開發的過程中,一定會碰上和貨幣打交道的程式碼。那麼這時候就會有一個問題?我們怎樣在資料庫中儲存貨幣單位呢?
使用整數型別
說實話,我到現在也是使用的這種方法。以分為單位,配合 Laravel Eloquent 中的 修改器 功能,可以很輕鬆的實現我想要的東西。
public function setPriceAttribute($value)
{
$this->attributes['price'] = intval($value * 100);
}
public function getPriceAttribute($value)
{
return $value / 100;
}
當然,專案裡的需求對精度沒有那麼高的要求,使用這種設計能符合我的需求。如果有更復雜的貨幣需求,這種設計可能就無法滿足了。
使用 Monetary types 型別
注意這個方法只適合 Postgresql 資料庫。有關介紹可以檢視官方文件。
舉個栗子
[local] =# CREATE TABLE money_example (cash money);
[local] =# INSERT INTO money_example VALUES ('$99.99');
[local] =# INSERT INTO money_example VALUES (99.99);
[local] =# INSERT INTO money_example VALUES (99.98996998);
[local] =# SELECT * FROM money_example;
cash
------------
$99.99
$99.99
$99.99
(3 row)
從上面的例子可以看出資料庫預設會為我們保留2位小數(四捨五入)。
看似很美好,是不是?但是有一個最大的問題是,我們只能使用一種貨幣單位,即要麼是美元,要麼是人民幣等,無法混著使用。如果只用一種貨幣的話,那麼可以考慮這種方法。
[local] =# INSERT INTO money_example VALUES ('¥99.99');
ERROR: 22P02: invalid input syntax for type money: "¥99.99"
LINE 1: INSERT INTO money_example VALUES ('¥99.99');
使用 decimal 型別
講道理的話,這個應該是最正確的用法了。直接上栗子。
[local] =# CREATE TABLE numeric_example ( numeric_cash NUMERIC(6, 4) );
[local] =# INSERT INTO numeric_example VALUES('99.9999');
[local] =# INSERT INTO numeric_example VALUES('99.998550');
[local] =# INSERT INTO numeric_example VALUES('99.998549');
[local] =# SELECT * FROM numeric_example;
numeric_cash
---------------
99.9999
99.9986
99.9985
(3 row)
在上面的例子中我們設定了6位數的長度,並且4位是小樹。當我們插入的資料長度不符合規格的時候就會丟擲錯誤(即,小數點前面的位數大於2的時候)。
[local] =# INSERT INTO numeric_example VALUES('999.99850');
ERROR: 22003: numeric field overflow
DETAIL: A field with precision 6, scale 4 must round to an absolute value less than 10^2.
LOCATION: apply_typmod, numeric.c:5998
參考文章
結語
以後在開發新專案的時候,我應該會使用最後一種方法來進行貨幣儲存。
不知道大家在開發中用的是哪種方法呢?