LoginSignup
6
7

More than 3 years have passed since last update.

PostgreSQLへの接続

Last updated at Posted at 2019-11-08

PostgreSQLへの接続を標準の[database/sql]を利用した場合と
ORMのGORMを利用した場合の比較しました。

標準

まずは、標準[database/sql]を利用した場合

main.go
package main

import (
    "database/sql"
    "fmt"
    "log"
    _ "github.com/lib/pq"
)

type Sale struct {
    Id   string
    OrderId string
}

func main() {
    db, err := sql.Open("postgres", "postgres://user:pass@host:port/dbname")
    if err != nil {
        log.Fatalln("接続失敗", err)
    }
    defer db.Close()

    // 取得件数を条件[$1]にする
    // ?だとエラーが発生
    //cmd := "select id, order_id from final_sales where id like $1"
    cmd := "select id, order_id from final_sales where id like $1"
    //取得するデータが1件の場合は、QueryRowも利用できる
    rows, _ := db.Query(cmd, "T00%")
    defer rows.Close()

    var sales []Sale // 取得するデータの構造体を用意(複数取得するのでスライス)
    for rows.Next() {
        var tmp Sale // 取得の格納用
        err := rows.Scan(&tmp.Id, &tmp.OrderId)
        if err != nil {
            log.Fatalln("取得失敗", err)
        }
        sales = append(sales, tmp)
    }
    for _, sale := range sales {
        fmt.Println(sale.Id, sale.OrderId)
    }
}

ORM

次にORM[gorm]を利用した場合

main.go
package main

import (
    "fmt"
    "log"

    "github.com/jinzhu/gorm"

    _ "github.com/lib/pq"
)

// `デフォルトのテーブル名は`sales`と自動判断
type Sale struct {
    Id   string `gorm:"column:sale_id"`
    OrderId string `gorm:"column:order_id"`
}

// 今回は、デフォルトではないので指定する
func (Sale) TableName() string {
    return "final_sales"
}

func main() {
    db, err := gorm.Open("postgres", "postgres://user:pass@host:port/dbname")
    if err != nil {
        log.Fatalln("接続失敗", err)
    }
    defer db.Close()

    var sales []Sale // 取得するデータの構造体を用意(複数取得するのでスライス)
    err = db.Where("sale_id like ?", "T00%").Find(&sales).Error

    if err != nil {
        log.Fatalln("取得失敗", err)
    }

    fmt.Println(sales)
}

相違点

import

database/sqlの代わりにgithub.com/jinzhu/gormをimportします。

接続方法

接続を sql.Open から gorm.Open に変更します。

構造体の宣言

構造体の宣言にgorm:"column:sale_id"を付与します。
これは、gormが自動でデータ取得する際の判断に用いられます。

なお、OrderIdはスネークケースとキャメルケースの変換が自動で行われます。
そのため、以下のようにカラム名の指定が無くても問題ありません。

type Sale struct {
    Id   string `gorm:"column:sale_id"`
    OrderId string
}

以下、サイトを参照
カラム名の指定方法

テーブル名の指定

gormでは宣言した構造体の複数形がテーブル名として自動判断されます。
今回は自動判断の名称と違うため、テーブル名を宣言しています。

func (Sale) TableName() string {
    return "final_sales"
}

以下を参照
複数形のテーブル名

データ取得方法

ORMなので、SQLを記述する必要がなくなります。
もちろん、SQLを記述することもできます。

標準だとfor文でデータを1件ずつ取得して構造体のスライスに格納していましたが、ORMを利用すると1発で取得できます。

err = db.Where("sale_id like ?", "T00%").Find(&sales).Error

以下を参照
WHERE
エラーハンドリング

まとめ

ローカルのSQLiteとサーバーにあるSQLSeverでSQLを別々に書いているプロジェクトを経験したことがあります。
ORMを知っていれば、このような煩わしい行為をしなくてすみそうです。
現在は、PostgreSQLへの接続情報を環境変数に用意して、環境変数を取得できない場合、ローカルの開発環境と判断し、SQLiteへ接続するようにしています。
生のSQLを記述していないため、今のところデータベースが変わってもエラーは発生していません。

ただ、通常のプロジェクトであれば、サーバーとローカルに同じデータベースを用意した方が、データベースの差異による挙動の違いも防げるので良いかと思います。
また、ORM特有の記述も覚える必要があるし。

参照

カラム名の指定方法
複数形のテーブル名
WHERE
エラーハンドリング

6
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
7