gorm:插入记录

2,304 阅读1分钟

建表语句:

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(23) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `birthday` timestamp NULL DEFAULT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

gorm有一个比较不好的默认设置,就是会把结构体名的复数当作数据库的表名,解决方法:实现TableName方法。

type User struct {
   ID        uint64
   Name      string
   Age       int8
   Birthday  time.Time
   CreatedAt time.Time
   UpdatedAt time.Time
}


// 去除默认的表名复数,以user作为表名
func (User) TableName() string {
   return "user"
}

插入记录:

func Create() {
   user := model.User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
   result := Db.Create(&user)

   //默认将表的主键赋值回结构体的ID字段
   fmt.Println(user.ID)
   printLine()
   fmt.Println(result.Error)
   printLine()
   fmt.Println(result.RowsAffected)
}

运行结果:

截屏2021-12-26 下午9.13.47.png


gorm约定,数据表的列名使用的是 struct 字段名的 蛇形命名,如:

type User struct {
  ID        uint      // 列名是 `id`
  Name      string    // 列名是 `name`
  Birthday  time.Time // 列名是 `birthday`
  CreatedAt time.Time // 列名是 `created_at`
}

我们也可以配置结构体字段与数据库列名的映射关系:

type Animal struct {
  AnimalID int64     `gorm:"column:beast_id"`         // 将列名设为 `beast_id`
  Birthday time.Time `gorm:"column:day_of_the_beast"` // 将列名设为 `day_of_the_beast`
  Age      int64     `gorm:"column:age_of_the_beast"` // 将列名设为 `age_of_the_beast`
}

只插入部分字段:

func Create2() {
   user := model.User{
      Name:     "空阿道夫",
      Birthday: time.Now(),
      Age:      22,
   }
   //birthday字段将被忽略,不会写入到数据库
   Db.Select("Name", "Age", "CreatedAt").Create(&user)
}

截屏2021-12-26 下午9.48.51.png

创建一个记录且一同忽略传递给略去的字段值。

Db.Omit("Name", "Age", "CreatedAt").Create(&user) 
// INSERT INTO `users` (`birthday`,`updated_at`) VALUES ("2020-01-01 00:00:00.000", "2020-07-04 11:05:21.775") 

批量插入

func genMockUser(n int) []*model.User {
   var res = make([]*model.User, n)
   for i := 0; i < n; i++ {
      res[i] = &model.User{
         Name:     "北包包",
         Age:      int8(i),
         Birthday: time.Now(), //一定要赋值,不然gorm会为它赋值为'0000-00-00',mysql会报错
      }
   }
   return res
}

func BatchInset() error {
   mockUsers := genMockUser(10)
   // 传递切片
   tx := Db.Create(&mockUsers)
   return tx.Error
}

但是出现了一个问题:Birthday属性是time.Time类型,所以插入时一定要为它赋值,不然会出现这样的错误:

Error 1292: Incorrect datetime value: '0000-00-00' for column 'birthday' at row 1

假如一定就是不想为Birthday字段赋值,有什么办法吗?

参考:gorm使结构体时间字段默认赋值null

方法就是把Birthday类型由time.Time类型转为sql.NullTime类型。

高级批量插入

使用 CreateInBatches 分批创建时,你可以指定每批的数量,例如:

var users = []User{{name: "warson_1"}, ...., {Name: "warson_10000"}}  
db.CreateInBatches(users, 100) // 每次批量插入100条记录

Upsert 和 Create With Associations 也支持批量插入

注意 使用CreateBatchSize 选项初始化 GORM 时,所有的创建& 关联 INSERT 都将遵循该选项

db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{
  CreateBatchSize: 1000,
})

参考: