GoのGormライブラリアップデートについて

始めました！株式会社メタップスホールディングスのジュリアンです！

今回の紹介はGo言語のGormライブラリの２件の違いを説明させてください。

## 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を使ってあなたのコードにインポートされる.


```go
import (
    ...
    "gorm.io/gorm"
)
```

(goのエコシステムのクセのため、v2はv1.20.0以上とタグ付けされていることを覚えておいてください。)

トランザクションが一番違いです

### jinzhu/gorm

古いGormのやり方はまだtransaction自身を自分で管理します。
最初はBeginをして、トランザクジョンを確認して、RollbackUnlessCommittedをdeferにお願いして、作成されたらLastで作成されたオブジェクトを取って、returnします。

```go
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がメモリに残ってます！

```go

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のメソットの中を見ると色々を任せ出来ます！


```go
// 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から移行する理由もたくさんある。