Mastering GORM: A Beginner’s Guide to Go ORM CRUD Operations

This article walks through setting up GORM in a Go project, covering dependency management, database initialization, model definition, and practical examples of select, insert, update, delete, raw SQL execution, and transaction handling with detailed code snippets.

FunTester
FunTester
FunTester
Mastering GORM: A Beginner’s Guide to Go ORM CRUD Operations

Introduction

GORM is a popular ORM library written in Go that offers comprehensive documentation and developer-friendly APIs for mainstream databases. The author, while consolidating knowledge of Go’s foundational libraries, chose GORM for its popularity and shares practical experiences for beginners.

go.mod Dependency

Add the GORM module to your project: github.com/jinzhu/gorm v1.9.16 Running go mod tidy automatically resolves and adds required dependencies to go.mod.

Import Statements

import (
    "fmt"
    "funtester/base"
    "funtester/futil"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/mysql"
    "log"
    "testing"
    "time"
)

Database Initialization

The following init function opens a MySQL connection, configures the connection pool, and auto‑migrates the schema.

func init() {
    var err error
    drive, err = gorm.Open("mysql", "root:root123456@(localhost:3306)/funtester?charset=utf8&parseTime=true")
    if err != nil {
        fmt.Println(err)
        log.Fatalln("mysql conntect err")
    }
    drive.DB().SetMaxOpenConns(200)
    drive.DB().SetConnMaxLifetime(10 * time.Second)
    drive.DB().SetConnMaxIdleTime(10 * time.Second)
    drive.DB().SetMaxIdleConns(20)
    // AutoMigrate creates missing tables, columns, indexes, and foreign keys but does not drop unused columns.
    drive.AutoMigrate(&Funtester{})
}

Model Definition

type Funtester struct {
    gorm.Model
    Name string
    Age  int
}

The corresponding MySQL table created by AutoMigrate looks like:

DROP TABLE IF EXISTS `funtesters`;
CREATE TABLE `funtesters` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` int unsigned DEFAULT NULL,
  `created_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  `deleted_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_funtesters_deleted_at` (`deleted_at`)
) ENGINE=InnoDB AUTO_INCREMENT=241861 DEFAULT CHARSET=utf8mb3;
SET FOREIGN_KEY_CHECKS = 1;

Source of gorm.Model:

type Model struct {
    ID        uint `gorm:"primary_key"`
    CreatedAt time.Time
    UpdatedAt time.Time
    DeletedAt *time.Time `sql:"index"`
}

Select Queries

Two example test functions demonstrate basic and complex query patterns.

func TestSelect1(t *testing.T) {
    var f Funtester
    drive.First(&f, 34) // primary key = 34
    last := drive.Last(&f, "age != 1") // add condition
    fmt.Printf("查询到记录数 %d "+base.LINE, last.RowsAffected)
    fmt.Println(f)
    take := drive.Take(&f) // no explicit order
    fmt.Println(take.RowsAffected)
}

func TestSelect2(t *testing.T) {
    var fs []Funtester
    var f Funtester
    drive.Where("id = ?", 45).First(&f) // alternative syntax
    find := drive.Where("name like ?", "fun%").Find(&fs).Limit(10).Order("id") // chained conditions
    rows, _ := find.Rows()
    defer rows.Close()
    for rows.Next() {
        var ff Funtester
        drive.ScanRows(rows, &ff)
        fmt.Println(ff.Age, ff.Name)
    }
    var f1 Funtester
    drive.Where("name LIKE ?", "fun").Or("id = ?", 123).First(&f1)
    fmt.Println(f1)
}

Update

func TestUpdate(t *testing.T) {
    drive.Model(&Funtester{}).Where("id = ?", 241860).Update("name", base.FunTester+"3")
}

Insert

GORM supports creating records, selecting specific fields, and omitting fields. Batch insert is not supported in the used version.

func TestInsert(t *testing.T) {
    value := &Funtester{Name: "FunTester" + futil.RandomStr(10)}
    drive.Create(value)
    drive.Select("name", "age").Create(value) // only name and age
    futil.Sleep(1)
    drive.Omit("age", "name").Create(&Funtester{Name: "fds", Age: 122}) // omit fields
    fs := []Funtester{{Name: "fs" + futil.RandomStr(10), Age: 12}, {Name: "fs" + futil.RandomStr(10), Age: 12}}
    drive.Create(&fs) // not supported in this version
}

Delete

func TestDelete(t *testing.T) {
    db := drive.Where("id = ?", 241859).Delete(&Funtester{})
    fmt.Println(db.RowsAffected)
}

Executing Raw SQL

func TestSql(t *testing.T) {
    var funtester []Funtester
    scan := drive.Raw("select * from funtesters where id > 333 limit 10").Scan(&funtester)
    fmt.Println(scan.RowsAffected)
    fmt.Println(funtester)
}

Transactions & Rollback

func TestRollBack(t *testing.T) {
    funtester := Funtester{Name: base.FunTester, Age: 32232}
    begin := drive.Begin()
    err := begin.Create(&funtester).Error
    if err != nil {
        begin.Rollback()
        return
    }
    begin.Commit()
}

Conclusion

The basic usage of GORM—including connection setup, model definition, CRUD operations, raw SQL execution, and transaction handling—has been covered. Future articles will explore performance testing with GORM.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackenddatabaseGoORMCRUDGORM
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.