地方网站有何作用,网站改版升级总结,wordpress添加支付教程,西安 网站空间优缺点
优点#xff1a;提高开发效率#xff0c;防止SQL注入、对不熟悉SQL语句的人友好、代码统一缺点#xff1a;牺牲执行能力、牺牲灵活性、弱化SQL能力
在一些小型项目上使用ORM可以大大提高开发效率#xff0c;但是在一些对性能要求高得场景下#xff0c;ORM可能没有…优缺点
优点提高开发效率防止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/mysqlgorm.io/gorm
)func main() {dsn : user:passtcp(127.0.0.1:3306)/dbname?charsetutf8mb4parseTimeTruelocLocaldb, err : gorm.Open(mysql.Open(dsn), gorm.Config{})
}MySQL驱动程序也提供了一些高级配置供程序员在初始化的过程中使用。 db, err : gorm.Open(mysql.New(mysql.Config{DSN: gorm:gormtcp(127.0.0.1:3306)/gorm?charsetutf8parseTimeTruelocLocal, // 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:primaryKeyCreatedAt 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 null、size, autoIncrement… 像 varbinary(8) 这样指定数据库数据类型也是支持的。在使用指定数据库数据类型时它需要是完整的数据库数据类型如MEDIUMINT UNSIGNED not NULL AUTO_INCREMENTserializer指定将数据序列化或反序列化到数据库中的序列化器, 例如: serializer:json/gob/unixtimesize定义列数据类型的大小或长度例如 size: 256primaryKey将列定义为主键unique将列定义为唯一键default定义列的默认值precision指定列的精度scale指定列大小not null指定列为 NOT NULLautoIncrement指定列为自动增长autoIncrementIncrement自动步长控制连续记录之间的间隔embedded嵌套字段embeddedPrefix嵌入字段的列名前缀autoCreateTime创建时追踪当前时间对于 int 字段它会追踪时间戳秒数您可以使用 nano/milli 来追踪纳秒、毫秒时间戳例如autoCreateTime:nanoautoUpdateTime创建/更新时追踪当前时间对于 int 字段它会追踪时间戳秒数您可以使用 nano/milli 来追踪纳秒、毫秒时间戳例如autoUpdateTime:milliindex根据参数创建索引多个字段使用相同的名称则创建复合索引查看 索引 获取详情uniqueIndex与 index 相同但创建的是唯一索引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 nullAge string gorm:column:age;type:intEmail string gorm:column:email;type:varchar(20);unique
}创建记录 我们可以通过gorm.Create()方法创建记录需要注意的是传递的参数是结构体指针而非结构体本身。此外gorm.Create()方法也可以创建多条记录。返回值Result有两个属性分别为创建记录错误Error和创建记录的条数RowAffected。 // 创建一条记录
user : User{Name: xiaoming, Age: 21, Email: XXXqq.com}
result : db.Create(user) // 通过数据的指针来创建// 创建多条记录
users : []*User{{Name: xiaoming, Age: 21, Email: XXXqq.com},{Name: ming, Age: 21, Email: YYYqq.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提供了First、Take和Last方法从数据库中检索单个对象。 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// doesnt 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方法中作为内联条件当然内联条件也可以写在First和Find中。
更新记录 Save会更新所有的字段即使字段是零值。 db.First(user)user.Name jinzhu 2
user.Age 100
db.Save(user)
// UPDATE users SET namejinzhu 2, age100, birthday2016-01-01, updated_at 2013-11-17 21:34:10 WHERE id111;Update可以更新单个列Updates可以更新多列Updates方法支持struct和map[string]interface{}参数。使用struct更新时Updates将只更新非零字段。 // 更新单列
// User 的 ID 是 111
db.Model(user).Update(name, hello)
// UPDATE users SET namehello, updated_at2013-11-17 21:34:10 WHERE id111;// 更新多列
// 根据 struct 更新属性只会更新非零值的字段
db.Model(user).Updates(User{Name: hello, Age: 18, Active: false})
// UPDATE users SET namehello, age18, 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 namehello, age18, activefalse, updated_at2013-11-17 21:34:10 WHERE id111;在更新时可以选择或者忽略某些字段如果需要选择某些字段可以使用Select如果需要忽略某些字段则可以使用Omit。 // 选择 Map 的字段
// User 的 ID 是 111:
db.Model(user).Select(name).Updates(map[string]interface{}{name: hello, age: 18, active: false})
// UPDATE users SET namehello WHERE id111;db.Model(user).Omit(name).Updates(map[string]interface{}{name: hello, age: 18, active: false})
// UPDATE users SET age18, activefalse, updated_at2013-11-17 21:34:10 WHERE id111;// 选择 Struct 的字段会选中零值的字段
db.Model(user).Select(Name, Age).Updates(User{Name: new_name, Age: 0})
// UPDATE users SET namenew_name, age0 WHERE id111;// 选择所有字段选择包括零值字段的所有字段
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
}上述提到的方法均会调用钩子函数如果想不调用钩子函数则可以使用UpdateColumn和UpdateCoulmns方法使用方式类似Update和Updates。 阻止全局更新 如果你执行一个没有任何条件的批量更新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 11db.Exec(UPDATE users SET name ?, jinzhu)
// UPDATE users SET name jinzhudb.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 支持 BeforeDelete、AfterDelete 等钩子函数在删除记录时会调用这些方法。 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 11db.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 id1;删除标志 默认情况下gorm.Model使用*time.Time作为DeletedAt 的字段类型不过软删除插件gorm.io/plugin/soft_delete同时也提供其他的数据格式支持 提示 当使用DeletedAt创建唯一复合索引时你必须使用其他的数据类型例如通过gorm.io/plugin/soft_delete插件将字段类型定义为unix时间戳等等 import gorm.io/plugin/soft_deletetype User struct {ID uintName string gorm:uniqueIndex:udx_nameDeletedAt soft_delete.DeletedAt gorm:uniqueIndex:udx_name
}Unix 时间戳使用unix时间戳作为删除标志 import gorm.io/plugin/soft_deletetype 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_deletetype 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.)