前言
由於 PostgreSQL 的 numeric 型別可以處理非常大的數字,因此在處理加密貨幣金額時,可以使用 PostgreSQL 來儲存。
以 Solidity 的 uint256 型別為例,可以使用數字型別的 numeric(78,0) 來儲存。
常用的數字型別如下:
| Type | Storage Size | Range | 
| smallint | 2 bytes | -32768 到 +32767 | 
| integer | 4 bytes | -2147483648 到 +2147483647 | 
| bigint | 8 bytes | -9223372036854775808 到 +9223372036854775807 | 
| numeric | variable | 小數點前 131,072 位,小數點後 16,383 位 | 
安裝套件
安裝套件。
| 12
 3
 4
 
 | go get github.com/joho/godotenvgo get gorm.io/gorm
 go get gorm.io/driver/postgres
 go get github.com/jackc/pgtype
 
 | 
連線
在 database.go 檔建立一個 DB() 方法,以建立連線並初始化一個 DB 實例。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | package database
 import (
 "fmt"
 "gorm.io/driver/postgres"
 "gorm.io/gorm"
 "log"
 "os"
 )
 
 func DB() *gorm.DB {
 dsn := fmt.Sprintf(
 "host=%s port=%s user=%s password=%s dbname=%s sslmode=disable",
 os.Getenv("DB_HOST"),
 os.Getenv("DB_PORT"),
 os.Getenv("DB_USERNAME"),
 os.Getenv("DB_PASSWORD"),
 os.Getenv("DB_DATABASE"),
 )
 db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
 if err != nil {
 log.Fatal(err)
 }
 return db
 }
 
 | 
定義模型
在 model/log.go 檔定義資料模型。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | package model
 import (
 "github.com/jackc/pgtype"
 "time"
 )
 
 type Log struct {
 TransactionHash    string         `gorm:"not null;type:char(66);primaryKey;" json:"transactionHash"`
 BlockNumber        uint64         `gorm:"not null;" json:"blockNumber"`
 EventName          string         `gorm:"not null;type:varchar(255);" json:"eventName"`
 Amount             pgtype.Numeric `gorm:"not null;type:numeric(78,0);" json:"amount"`
 CreatedAt          time.Time      `gorm:"not null;" json:"createdAt"`
 UpdatedAt          time.Time      `gorm:"not null;" json:"updatedAt"`
 }
 
 | 
- TransactionHash為 64 個固定字元再加上- 0x前綴,因此使用- char(66)來儲存。
- EventName為一個簡短的可變字串,因此使用- varchar(255)來儲存。
- Amount為一個龐大數字(- uint256),因此使用- numeric(78,0)來儲存。
數字轉型
轉換 big.Int 型別到 pgtype.Numeric 型別。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | import ("github.com/jackc/pgtype"
 )
 
 func ToNumeric(v interface{}) *pgtype.Numeric {
 n := pgtype.Numeric{}
 if err := n.Set(v); err != nil {
 log.Fatal(err)
 }
 return &n
 }
 
 | 
新增資料
新增多資料。
| 1
 | database.DB().Create(logs)
 | 
批次新增資料。
| 1
 | database.DB().CreateInBatches(logs, 100)
 | 
型別擴充
如果需要將 Numeric 序列化或反序列化,需要改用 shopspring-numeric 包。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | package model
 import (
 "github.com/jackc/pgtype/ext/shopspring-numeric"
 )
 
 type Log struct {
 
 Amount             pgtype.Numeric `gorm:"not null;type:numeric(78,0);" json:"amount"`
 
 }
 
 | 
遷移
在 database.go 檔建立一個 Migrate() 方法,以新增資料表。
| 12
 3
 4
 5
 6
 7
 
 | func Migrate() {if err := DB().AutoMigrate(
 &model.Log{},
 ); err != nil {
 log.Fatal(err)
 }
 }
 
 | 
參考資料