您的位置:首页 > 房产 > 家装 > 中国公司排名100强_教育网站制作服务_西安网站优化推广方案_关键词如何快速排名

中国公司排名100强_教育网站制作服务_西安网站优化推广方案_关键词如何快速排名

2025/2/25 14:08:36 来源:https://blog.csdn.net/qq_72363261/article/details/145764131  浏览:    关键词:中国公司排名100强_教育网站制作服务_西安网站优化推广方案_关键词如何快速排名
中国公司排名100强_教育网站制作服务_西安网站优化推广方案_关键词如何快速排名

优缺点

  • 优点:提高开发效率,防止SQL注入、对不熟悉SQL语句的人友好、代码统一
  • 缺点:牺牲执行能力、牺牲灵活性、弱化SQL能力

在一些小型项目上使用ORM可以大大提高开发效率,但是在一些对性能要求高得场景下,ORM可能没有那么合适。

环境配置

  • GORM:在命令行中输入如下命令go get -u github.com/jinzhu/gorm即可安装GORM。

  • MySQL:请参考MySQL安装教程。

连接数据库

  • GROM官方支持的数据库类型有:MySQL、PostgreSQL, SQLite, SQL Server 和 TiDB。

  • 以连接MySQL为例,GORM连接MySQL非常简单,其代码如下:

    import ("gorm.io/driver/mysql""gorm.io/gorm"
    )func main() {dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    }
    
  • MySQL驱动程序也提供了一些高级配置供程序员在初始化的过程中使用。

    db, err := gorm.Open(mysql.New(mysql.Config{DSN: "gorm:gorm@tcp(127.0.0.1:3306)/gorm?charset=utf8&parseTime=True&loc=Local", // DSN data source nameDefaultStringSize: 256, // string 类型字段的默认长度DisableDatetimePrecision: true, // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引DontSupportRenameColumn: true, // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置
    }), &gorm.Config{})
    

模型默认相关

  • GORM提供了一个预定义的结构体,名为gorm.Model,其中包含常用字段:ID为默认的主键;CreatedAt记录了该记录被创建的时间;UpdatedAt记录该记录被更新的时间;DeletedAt记录了该记录被删除的时间,因为GORM中的Delete是软删除。

    // gorm.Model 的定义
    type Model struct {ID        uint           `gorm:"primaryKey"`CreatedAt time.TimeUpdatedAt time.TimeDeletedAt gorm.DeletedAt `gorm:"index"`
    }
    
  • 将其嵌入结构体中: 可以直接在结构体中嵌入 gorm.Model ,以便自动包含这些字段。 这对于在不同模型之间保持一致性并利用GORM内置的约定非常有用。当然,我们也可以手动创建。

  • 包含的字段

    • ID :每个记录的唯一标识符(主键)。
    • CreatedAt :在创建记录时自动设置为当前时间。
    • UpdatedAt:每当记录更新时,自动更新为当前时间。
    • DeletedAt:用于软删除(将记录标记为已删除,而实际上并未从数据库中删除)
  • GORM中常见的结构体tag:

    标签名说明
    column指定 db 列名
    type列数据类型,推荐使用兼容性好的通用类型,例如:所有数据库都支持 bool、int、uint、float、string、time、bytes 并且可以和其他标签一起使用,例如:not nullsize, autoIncrement… 像 varbinary(8) 这样指定数据库数据类型也是支持的。在使用指定数据库数据类型时,它需要是完整的数据库数据类型,如:MEDIUMINT UNSIGNED not NULL AUTO_INCREMENT
    serializer指定将数据序列化或反序列化到数据库中的序列化器, 例如: serializer:json/gob/unixtime
    size定义列数据类型的大小或长度,例如 size: 256
    primaryKey将列定义为主键
    unique将列定义为唯一键
    default定义列的默认值
    precision指定列的精度
    scale指定列大小
    not null指定列为 NOT NULL
    autoIncrement指定列为自动增长
    autoIncrementIncrement自动步长,控制连续记录之间的间隔
    embedded嵌套字段
    embeddedPrefix嵌入字段的列名前缀
    autoCreateTime创建时追踪当前时间,对于 int 字段,它会追踪时间戳秒数,您可以使用 nano/milli 来追踪纳秒、毫秒时间戳,例如:autoCreateTime:nano
    autoUpdateTime创建/更新时追踪当前时间,对于 int 字段,它会追踪时间戳秒数,您可以使用 nano/milli 来追踪纳秒、毫秒时间戳,例如:autoUpdateTime:milli
    index根据参数创建索引,多个字段使用相同的名称则创建复合索引,查看 索引 获取详情
    uniqueIndexindex 相同,但创建的是唯一索引
    check创建检查约束,例如 check:age > 13,查看 约束 获取详情
    <-设置字段写入的权限, <-:create 只创建、<-:update 只更新、<-:false 无写入权限、<- 创建和更新权限
    ->设置字段读的权限,->:false 无读权限
    -忽略该字段,- 表示无读写,-:migration 表示无迁移权限,-:all 表示无读写迁移权限
    comment迁移时为字段添加注释
    • 使用方法如下:

      type User struct {gorm.ModelUserName string `gorm:"column:user_name;type:varchar(20);not null"`Age string `gorm:"column:age;type:int"`Email string `gorm:"column:email;type:varchar(20);unique"`
      }
      

创建记录

  • 我们可以通过gorm.Create()方法创建记录,需要注意的是传递的参数是结构体指针,而非结构体本身。此外,gorm.Create()方法也可以创建多条记录。返回值Result有两个属性,分别为创建记录错误Error和创建记录的条数RowAffected

    // 创建一条记录
    user := User{Name: "xiaoming", Age: 21, Email: "XXX@qq.com"}
    result := db.Create(&user) // 通过数据的指针来创建// 创建多条记录
    users := []*User{{Name: "xiaoming", Age: 21, Email: "XXX@qq.com"},{Name: "ming", Age: 21, Email: "YYY@qq.com"},
    }
    result := db.Create(users) // 传递切片
    
  • 创建记录并为指定字段赋值。

    db.Select("Name", "Age", "CreatedAt").Create(&user)
    
  • 创建记录并忽略传递给 ‘Omit’ 的字段值

    db.Omit("Name", "Age", "CreatedAt").Create(&user)
  • 使用钩子函数:GORM允许用户通过实现这些接口 BeforeSave, BeforeCreate, AfterSave, AfterCreate来自定义钩子。 这些钩子方法会在创建一条记录时被调用。

    func (u *User) BeforeCreate(tx *gorm.DB) (err error) {u.UUID = uuid.New()if u.Role == "admin" {return errors.New("invalid role")}return
    }
    

    如果你想跳过Hooks方法,可以使用SkipHooks会话模式,例子如下

    DB.Session(&gorm.Session{SkipHooks: true}).Create(&user)DB.Session(&gorm.Session{SkipHooks: true}).Create(&users)DB.Session(&gorm.Session{SkipHooks: true}).CreateInBatches(users, 100)
    

查询记录

  • GORM提供了FirstTakeLast方法从数据库中检索单个对象。

  • First and Last 方法会按主键排序找到第一条记录和最后一条记录 (分别)。 只有在目标struct是指针或者通过db.Model()指定 model 时,该方法才有效。 此外,如果相关model没有定义主键,那么将按model的第一个字段进行排序。 例如:

    var user User
    var users []User// works because destination struct is passed in
    db.First(&user)
    // SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 1// works because model is specified using `db.Model()`
    result := map[string]interface{}{}
    db.Model(&User{}).First(&result)
    // SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 1// doesn't work
    result := map[string]interface{}{}
    db.Table("users").First(&result)// works with Take
    result := map[string]interface{}{}
    db.Table("users").Take(&result)// no primary key defined, results will be ordered by first field (i.e., `Code`)
    type Language struct {Code stringName string
    }
    db.First(&Language{})
    // SELECT * FROM `languages` ORDER BY `languages`.`code` LIMIT 1
    
  • 如果主键是数字类型,可以使用来检索对象。 当使用字符串时,需要额外的注意来避免SQL注入。

    db.First(&user, 10)
    // SELECT * FROM users WHERE id = 10;db.First(&user, "10")
    // SELECT * FROM users WHERE id = 10;db.Find(&users, []int{1,2,3})
    // SELECT * FROM users WHERE id IN (1,2,3);
    

    如果主键是字符串(例如像uuid),查询将被写成如下:

    db.First(&user, "id = ?", "1b74413f-f3b8-409f-ac47-e8c062e3472a")
    // SELECT * FROM users WHERE id = "1b74413f-f3b8-409f-ac47-e8c062e3472a";
    

    当目标对象有一个主键值时,将使用主键构建查询条件,例如:

    var user = User{ID: 10}
    db.First(&user)
    // SELECT * FROM users WHERE id = 10;var result User
    db.Model(User{ID: 10}).First(&result)
    // SELECT * FROM users WHERE id = 10;
    

    如果对象设置了主键,条件查询将不会覆盖主键的值,而是用And连接条件。 例如:

    var user = User{ID: 10}
    db.Where("id = ?", 20).First(&user)
    // SELECT * FROM users WHERE id = 10 and id = 20 ORDER BY id ASC LIMIT 1
    

    这个查询将会给出record not found错误 所以,在你想要使用例如 user 这样的变量从数据库中获取新值前,需要将例如 id 这样的主键设置为nil。

  • 检索全部对象

    result := db.Find(&users)
    // SELECT * FROM users;
    
  • 我们可以使用Limit方法限制查询结果的条数

    result := db.Limit(1).Find(&users)
    // SELECT * FROM users LIMIT 1;
    
  • 使用struct和map作为条件进行查询

    // Struct
    db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)
    // SELECT * FROM users WHERE name = "jinzhu" AND age = 20 ORDER BY id LIMIT 1;// Map
    db.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).Find(&users)
    // SELECT * FROM users WHERE name = "jinzhu" AND age = 20;// Slice of primary keys
    db.Where([]int64{20, 21, 22}).Find(&users)
    // SELECT * FROM users WHERE id IN (20, 21, 22);
    
  • 个人觉得这一部分和原生的MySQL查询非常地像,只是将一些条件变成了函数,另外一些条件写在Where方法中作为内联条件,当然,内联条件也可以写在FirstFind中。

更新记录

  • Save会更新所有的字段,即使字段是零值。

    db.First(&user)user.Name = "jinzhu 2"
    user.Age = 100
    db.Save(&user)
    // UPDATE users SET name='jinzhu 2', age=100, birthday='2016-01-01', updated_at = '2013-11-17 21:34:10' WHERE id=111;
    
  • Update可以更新单个列,Updates可以更新多列,Updates方法支持structmap[string]interface{}参数。使用struct更新时,Updates将只更新非零字段。

    // 更新单列
    // User 的 ID 是 `111`
    db.Model(&user).Update("name", "hello")
    // UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;// 更新多列
    // 根据 `struct` 更新属性,只会更新非零值的字段
    db.Model(&user).Updates(User{Name: "hello", Age: 18, Active: false})
    // UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 21:34:10' WHERE id = 111;// 根据 `map` 更新属性
    db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
    // UPDATE users SET name='hello', age=18, active=false, updated_at='2013-11-17 21:34:10' WHERE id=111;
    
  • 在更新时可以选择或者忽略某些字段,如果需要选择某些字段,可以使用Select;如果需要忽略某些字段,则可以使用Omit

    // 选择 Map 的字段
    // User 的 ID 是 `111`:
    db.Model(&user).Select("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
    // UPDATE users SET name='hello' WHERE id=111;db.Model(&user).Omit("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
    // UPDATE users SET age=18, active=false, updated_at='2013-11-17 21:34:10' WHERE id=111;// 选择 Struct 的字段(会选中零值的字段)
    db.Model(&user).Select("Name", "Age").Updates(User{Name: "new_name", Age: 0})
    // UPDATE users SET name='new_name', age=0 WHERE id=111;// 选择所有字段(选择包括零值字段的所有字段)
    db.Model(&user).Select("*").Updates(User{Name: "jinzhu", Role: "admin", Age: 0})// 选择除 Role 外的所有字段(包括零值字段的所有字段)
    db.Model(&user).Select("*").Omit("Role").Updates(User{Name: "jinzhu", Role: "admin", Age: 0})
    
  • GORM 支持的 hook 包括:BeforeSave, BeforeUpdate, AfterSave, AfterUpdate. 更新记录时将调用这些方法。

    func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {if u.Role == "admin" {return errors.New("admin user not allowed to update")}return
    }
    
  • 上述提到的方法均会调用钩子函数,如果想不调用钩子函数,则可以使用UpdateColumnUpdateCoulmns方法,使用方式类似UpdateUpdates

  • 阻止全局更新

    如果你执行一个没有任何条件的批量更新,GORM 默认不会运行,并且会返回 ErrMissingWhereClause 错误

    你可以用一些条件,使用原生 SQL 或者启用 AllowGlobalUpdate 模式,例如:

    db.Model(&User{}).Update("name", "jinzhu").Error // gorm.ErrMissingWhereClausedb.Model(&User{}).Where("1 = 1").Update("name", "jinzhu")
    // UPDATE users SET `name` = "jinzhu" WHERE 1=1db.Exec("UPDATE users SET name = ?", "jinzhu")
    // UPDATE users SET name = "jinzhu"db.Session(&gorm.Session{AllowGlobalUpdate: true}).Model(&User{}).Update("name", "jinzhu")
    // UPDATE users SET `name` = "jinzhu"
    

删除记录

  • 删除记录时需要指定主键,否则会触发批量删除

    // User的ID是1
    db.Delete(&user)
    // DELETE from users where id = 10;// User没有ID
    db.Delete(&user)
    // DELETE from users;
    
  • 当然,我们可以使用带额外条件的删除避免批量删除

    db.Where("name = ?", "xiaoming").Delete(&user)
    // DELETE from users where name = "xiaoming";
    
  • 使用钩子函数

    对于删除操作,GORM 支持 BeforeDeleteAfterDelete 等钩子函数,在删除记录时会调用这些方法。

    func (u *User) BeforeDelete(tx *gorm.DB) (err error) {    if u.Role == "admin" {        return errors.New("admin user not allowed to delete")    }    return
    }
    
  • 阻止全局删除

    当你试图执行不带任何条件的批量删除时,GORM将不会运行并返回ErrMissingWhereClause 错误

    如果一定要这么做,你必须添加一些条件,或者使用原生SQL,或者开启AllowGlobalUpdate 模式,如下例:

    db.Delete(&User{}).Error // gorm.ErrMissingWhereClausedb.Delete(&[]User{{Name: "jinzhu1"}, {Name: "jinzhu2"}}).Error // gorm.ErrMissingWhereClausedb.Where("1 = 1").Delete(&User{})
    // DELETE FROM `users` WHERE 1=1db.Exec("DELETE FROM users")
    // DELETE FROM usersdb.Session(&gorm.Session{AllowGlobalUpdate: true}).Delete(&User{})
    // DELETE FROM users
    
  • 软删除

    如果模型中包含了gorm.DeleteAt字段,则模型会自动获得软删除的能力,反之则没有软删除的能力。

    在有软删除能力的情况下调用Delete函数,GORM并不会从数据库中删除该记录,而是将该记录的DeleteAt设置为当前时间,而后的一般查询方法将无法查找到此条记录。

  • 查找被软删除的记录:可以使用gorm.Unscoped()方法实现。

    db.Unscoped().Where("age = 21").Find(&users)
    
  • 永久删除:可以使用 Unscoped来永久删除匹配的记录

    // User的ID是1
    db.Unscoped().Delete(&user)
    // DELETE FROM order WHERE id=1;
    
  • 删除标志

    默认情况下,gorm.Model使用*time.Time作为DeletedAt 的字段类型,不过软删除插件gorm.io/plugin/soft_delete同时也提供其他的数据格式支持

    提示 当使用DeletedAt创建唯一复合索引时,你必须使用其他的数据类型,例如通过gorm.io/plugin/soft_delete插件将字段类型定义为unix时间戳等等

    import "gorm.io/plugin/soft_delete"type User struct {ID        uintName      string                `gorm:"uniqueIndex:udx_name"`DeletedAt soft_delete.DeletedAt `gorm:"uniqueIndex:udx_name"`
    }
    
    • Unix 时间戳:使用unix时间戳作为删除标志
    import "gorm.io/plugin/soft_delete"type User struct {ID        uintName      stringDeletedAt soft_delete.DeletedAt
    }// 查询
    SELECT * FROM users WHERE deleted_at = 0;// 软删除
    UPDATE users SET deleted_at = /* current unix second */ WHERE ID = 1;
    
    • 使用 1 / 0 作为 删除标志
    import "gorm.io/plugin/soft_delete"type User struct {ID    uintName  stringIsDel soft_delete.DeletedAt `gorm:"softDelete:flag"`
    }// 查询
    SELECT * FROM users WHERE is_del = 0;// 软删除
    UPDATE users SET is_del = 1 WHERE ID = 1;
    
    • 混合模式:混合模式可以使用 01或者unix时间戳来标记数据是否被软删除,并同时可以保存被删除时间
    type User struct {ID        uintName      stringDeletedAt time.TimeIsDel     soft_delete.DeletedAt `gorm:"softDelete:flag,DeletedAtField:DeletedAt"` // use `1` `0`// IsDel     soft_delete.DeletedAt `gorm:"softDelete:,DeletedAtField:DeletedAt"` // use `unix second`// IsDel     soft_delete.DeletedAt `gorm:"softDelete:nano,DeletedAtField:DeletedAt"` // use `unix nano second`
    }// 查询
    SELECT * FROM users WHERE is_del = 0;// 软删除
    UPDATE users SET is_del = 1, deleted_at = /* current unix second */ WHERE ID = 1;
    

参考文章

  • [【官方文档】GORM指南](GORM 指南 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com