始めました!株式会社メタップスホールディングスのジュリアンです!
今回の紹介はGo言語のGormライブラリの2件の違いを説明させてください。
Gorm ライブラリの紹介
デベロッパーフレンドリーを目指した、Go言語のORMライブラリです。DBと連携出来て、mysql、postgreなどのクエリが出来るようになります。
Gormのバージョン1からv1.9.16まではgithub.com/jinzhu/gormに保存されており、あなたのコードからインポートするにはそのパスを使う.
Goの慣例では、新しいパッケージ・バージョンが後方互換性を失った場合、インポート・パスを変更する必要がある。そこで、バージョン2をリリースする際、チームはgithubの新しい組織( https://github.com/go-gorm/gorm
)にレポを移動することにした。この新しいバージョンは、gorm.io/gormを使ってあなたのコードにインポートされる.
import (
...
"gorm.io/gorm"
)
(goのエコシステムのクセのため、v2はv1.20.0以上とタグ付けされていることを覚えておいてください。)
トランザクションが一番違いです
jinzhu/gorm
古いGormのやり方はまだtransaction自身を自分で管理します。
最初はBeginをして、トランザクジョンを確認して、RollbackUnlessCommittedをdeferにお願いして、作成されたらLastで作成されたオブジェクトを取って、returnします。
func (repository *someRepository) CreateTask(entity *some.Task) (*some.Task, error) {
tx := repository.DB.Begin()
if tx.Error != nil {
return nil, errors.Wrap(tx.Error, "failed to begin transaction")
}
defer func() {
if err := tx.RollbackUnlessCommitted().Error; err != nil {
log.Error("failed to rollback transaction", zap.Error(err))
}
}()
if err := tx.Create(entity).Error; err != nil {
return nil, errors.Wrap(err, "failed to create task")
}
var lastEntity some.Task
if err := tx.Last(&lastEntity).Error; err != nil {
return nil, errors.Wrap(err, "failed to get last task")
}
if err := tx.Commit().Error; err != nil {
return nil, errors.Wrap(err, "failed to commit while creating task")
}
return &lastEntity, nil
}
gorm.io
今回は全部同じメソットでまとめるようになってます!それでLastを使わないくてもそのままにentityがメモリに残ってます!
func (repository *someRepository) CreateTask(entity *some.Task) error {
return repository.gormIOdb.Transaction(func(tx *gormio.DB) error {
if err := tx.Create(&entity).Error; err != nil {
return errors.Wrap(err, "failed to create task")
}
return nil
}
}
Transactionのメソットの中を見ると色々を任せ出来ます!
// Transaction start a transaction as a block, return error will rollback, otherwise to commit. Transaction executes an
// arbitrary number of commands in fc within a transaction. On success the changes are committed; if an error occurs
// they are rolled back.
func (db *DB) Transaction(fc func(tx *DB) error, opts ...*sql.TxOptions) (err error) {
panicked := true
if committer, ok := db.Statement.ConnPool.(TxCommitter); ok && committer != nil {
// nested transaction
if !db.DisableNestedTransaction {
err = db.SavePoint(fmt.Sprintf("sp%p", fc)).Error
if err != nil {
return
}
defer func() {
// Make sure to rollback when panic, Block error or Commit error
if panicked || err != nil {
db.RollbackTo(fmt.Sprintf("sp%p", fc))
}
}()
}
err = fc(db.Session(&Session{NewDB: db.clone == 1}))
} else {
tx := db.Begin(opts...)
if tx.Error != nil {
return tx.Error
}
defer func() {
// Make sure to rollback when panic, Block error or Commit error
if panicked || err != nil {
tx.Rollback()
}
}()
if err = fc(tx); err == nil {
panicked = false
return tx.Commit().Error
}
}
panicked = false
return
}
CommitのステータスやまたはBeginがメソットに入ってます!deferも自分でしなくてもTransactionが全部やってます!
まとめ
Gorm v2は、構文や機能はv1にかなり近いですが、より強力で一貫性があり、多くのバグが取り除かれています。ベンチマークはまだ見ていませんが、プリペアドステートメントを使用することにより、より高性能になっているはずです。
全体として、新しいプロジェクトでv2を使わない理由はないし、既存のプロジェクトでv1から移行する理由もたくさんある。