wordpress网站变灰,哈尔滨seo优化培训,泗县口碑营销互联网营销推荐咨询,wordpress 监督投诉1. 什么是orm
ORM全称是#xff1a;Object Relational Mapping(对象关系映射)#xff0c;其主要作用是在编程中#xff0c;把面向对象的概念跟数据库中表的概念对应起来。举例来说就是#xff0c;我定义一个对象#xff0c;那就对应着一张表#xff0c;这个对象的实例Object Relational Mapping(对象关系映射)其主要作用是在编程中把面向对象的概念跟数据库中表的概念对应起来。举例来说就是我定义一个对象那就对应着一张表这个对象的实例就对应着表中的一条记录。 对于数据来说最重要最常用的是表表中有列 orm就是将一张表映射成一个类表中的列映射成类中的一个类。java 、python但是针对go语言而言struct就是列如何映射是因为列可以映射成struct中的类型int-int,但是有另一个问题 就是数据库中的列具备很好的描述性但是struct有tag(标签)。执行sql 需要我们有足够的sql语句基础、需要我们懂得不同的数据的sql
2. 常用orm
个人而言不用太去纠结应该选择哪一个orm框架但是实际上你用熟悉了一个其他的orm迁移成本很低我们选个一个star数量最高的一定不会有错这些差异也不会很大sql语言远比orm重要的多 https://github.com/go-gorm/gorm https://github.com/facebook/ent https://github.com/jmoiron/sqlx https://gitea.com/xorm/xorm/src/branch/master/README_CN.md https://github.com/didi/gendry/blob/master/translation/zhcn/README.md
gorm文档
https://gorm.io/zh_CN/docs/create.html3. orm的优缺点
优点
提高了开发效率。屏蔽sql细节。可以自动对实体Entity对象与数据库中的Table进行字段与属性的映射不用直接SQL编码屏蔽各种数据库之间的差异
缺点
orm会牺牲程序的执行效率和会固定思维模式太过依赖orm会导致sql理解不够对于固定的orm依赖过重导致切换到其他的orm代价高
4. 如何正确看待orm和sql之间的关系
sql为主orm为辅orm主要目的是为了增加代码可维护性和开发效率
gorm连接数据库
package mainimport (gorm.io/driver/mysqlgorm.io/gorm
)func main() {// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情//loc 本地时区//想要正确的处理 time.Time 您需要带上 parseTime 参数dsn : root:roottcp(192.168.0.102:3306)/gorm_test?charsetutf8mb4parseTimeTruelocLocal_, err : gorm.Open(mysql.Open(dsn), gorm.Config{})if err ! nil {panic(err)}}注意想要正确的处理 time.Time 您需要带上 parseTime 参数 (更多参数) 要支持完整的 UTF-8 编码您需要将 charsetutf8 更改为 charsetutf8mb4 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{})//设置全局的logger这个logger在我们执行每个sql语句的时候会打印每一行sql
日志
Gorm 有一个 默认 logger 实现默认情况下它会打印慢 SQL 和错误
Logger 接受的选项不多您可以在初始化时自定义它例如
newLogger : logger.New(log.New(os.Stdout, \r\n, log.LstdFlags), // io writerlogger.Config{SlowThreshold: time.Second, // Slow SQL thresholdLogLevel: logger.Silent, // Log levelIgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound error for loggerParameterizedQueries: true, // Dont include params in the SQL logColorful: false, // Disable color},
)// Globally mode
db, err : gorm.Open(sqlite.Open(test.db), gorm.Config{Logger: newLogger,
})// Continuous session mode
tx : db.Session(Session{Logger: newLogger})
tx.First(user)
tx.Model(user).Update(Age, 18)日志级别
GORM 定义了这些日志级别Silent、Error、Warn、Info
db, err : gorm.Open(sqlite.Open(test.db), gorm.Config{Logger: logger.Default.LogMode(logger.Silent),
})Debug
Debug 单个操作将当前操作的 log 级别调整为 logger.Info
db.Debug().Where(name ?, jinzhu).First(User{})自定义 Logger
参考 GORM 的 默认 logger 来定义您自己的 logger
Logger 需要实现以下接口它接受 context所以你可以用它来追踪日志
type Interface interface {LogMode(LogLevel) InterfaceInfo(context.Context, string, ...interface{})Warn(context.Context, string, ...interface{})Error(context.Context, string, ...interface{})Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error)
}创建表
_ db.AutoMigrate(Product{}) //此次应该有sql语句跟日志级别有关系通过NullString解决不能更新零值的问题 整体源码
package mainimport (database/sqlgorm.io/driver/mysqlgorm.io/gormgorm.io/gorm/loggerlogostime
)type Product struct {gorm.Model//Code stringCode sql.NullStringPrice uint
}func main() {// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情//loc 本地时区//想要正确的处理 time.Time 您需要带上 parseTime 参数dsn : root:roottcp(192.168.0.102:3306)/gorm_test?charsetutf8mb4parseTimeTruelocLocalnewLogger : logger.New(log.New(os.Stdout, \r\n, log.LstdFlags), // io writerlogger.Config{SlowThreshold: time.Second, // 慢SQL阈值LogLevel: logger.Info, // 日志级别// 忽略记录器的ErrRecordNotFound错误 是否忽略 record not found 错误默认为 false如果设置为 true则在查询结果为空时不会打印 record not found 错误信息IgnoreRecordNotFoundError: false,ParameterizedQueries: false, // 不要在SQL日志中包含参数Colorful: true, // 禁言彩色打印},)db, err : gorm.Open(mysql.Open(dsn), gorm.Config{Logger: newLogger,})if err ! nil {panic(err)}//设置全局的logger这个logger在我们执行每个sql语句的时候会打印每一行sql//定义一个表结构将表结构直接生成对应的表---migrations(迁移)//迁移_ db.AutoMigrate(Product{}) //此次应该有sql语句// 新增//db.Create(Product{Code: D42, Price: 100})db.Create(Product{Code: sql.NullString{D42, true}, Price: 100})// 查询var product Productdb.First(product, 1) // 根据整型主键查找db.First(product, code ?, D42) // 查找 code 字段值为 D42 的记录// 更新一个值 - 将 product 的 price 更新为 200db.Model(product).Update(Price, 200)// Update - 更新多个字段//db.Model(product).Updates(Product{Price: 200, Code: F42}) // 仅更新非零值字段db.Model(product).Updates(Product{Price: 200, Code: sql.NullString{String: , Valid: true}}) // 仅更新非零值字段//db.Model(product).Updates(map[string]interface{}{Price: 200, Code: F42})// Delete - 删除 product//并没有执行deleta语句而是逻辑删除//db.Delete(product, 1)
}解决仅更新非零值字段的方法有两种 /**1 将string设置为*string2 使用sql的NULLxxx来结局*/empty : db.Model(User{ID: 1}).Updates(User{Email: empty})//updates语句不会更新零值但update语句会更新//db.Model(User{ID: 1}).Update(Name, )//db.Model(User{ID: 1}).Updates(User{Name: })约定
GORM 倾向于约定优于配置 默认情况下GORM 使用 ID 作为主键使用结构体名的 蛇形复数 作为表名字段名的 蛇形 作为列名并使用 CreatedAt、UpdatedAt 字段追踪创建、更新时间 如果您遵循 GORM 的约定您就可以少写的配置、代码。 如果约定不符合您的实际要求GORM 允许你配置它们
嵌入结构体
对于匿名字段GORM 会将其字段包含在父结构体中例如
type User struct {gorm.ModelName string
}
// 等效于
type User struct {ID uint gorm:primaryKeyCreatedAt time.TimeUpdatedAt time.TimeDeletedAt gorm.DeletedAt gorm:indexName string
}对于正常的结构体字段你也可以通过标签 embedded 将其嵌入例如
type Author struct {Name stringEmail string
}type Blog struct {ID intAuthor Author gorm:embeddedUpvotes int32
}
// 等效于
type Blog struct {ID int64Name stringEmail stringUpvotes int32
}并且您可以使用标签 embeddedPrefix 来为 db 中的字段名添加前缀例如
type Blog struct {ID intAuthor Author gorm:embedded;embeddedPrefix:author_Upvotes int32
}
// 等效于
type Blog struct {ID int64AuthorName stringAuthorEmail stringUpvotes int32
}字段标签
声明 model 时tag 是可选的GORM 支持以下 tag tag 名大小写不敏感但建议使用 camelCase 风格–去官网看源码
package mainimport (gorm.io/driver/mysqlgorm.io/gormgorm.io/gorm/loggerlogostime
)type User struct {UserID uint gorm:primarykeyName string gorm:column:user_name;type:varchar(50);index:idx_user_name;unique;default:bobby
}func main() {// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情//loc 本地时区//想要正确的处理 time.Time 您需要带上 parseTime 参数dsn : root:roottcp(192.168.0.102:3306)/gorm_test?charsetutf8mb4parseTimeTruelocLocalnewLogger : logger.New(log.New(os.Stdout, \r\n, log.LstdFlags), // io writerlogger.Config{SlowThreshold: time.Second, // 慢SQL阈值LogLevel: logger.Info, // 日志级别IgnoreRecordNotFoundError: false,ParameterizedQueries: false, // 不要在SQL日志中包含参数Colorful: true, // 禁言彩色打印},)db, err : gorm.Open(mysql.Open(dsn), gorm.Config{Logger: newLogger,})if err ! nil {panic(err)}_ db.AutoMigrate(User{}) //此次应该有sql语句db.Create(User{})}通过create方法插入记录
user : User{Name: Jinzhu, Age: 18, Birthday: time.Now()}result : db.Create(user) // 通过数据的指针来创建user.ID // 返回插入数据的主键
result.Error // 返回 error
result.RowsAffected // 返回插入记录的条数我们还可以使用 Create() 创建多项记录
users : []*User{User{Name: Jinzhu, Age: 18, Birthday: time.Now()},User{Name: Jackson, Age: 19, Birthday: time.Now()},
}result : db.Create(users) // 传递切片以插入多行数据result.Error // 返回 error
result.RowsAffected // 返回插入记录的条数package mainimport (database/sqlfmtgorm.io/driver/mysqlgorm.io/gormgorm.io/gorm/loggerlogostime
)type User struct {ID uintName stringEmail *string //使用指针的方法解决空字符串Age uint8Birthday *time.TimeMemberNumber sql.NullStringActivatedAt sql.NullTimeCreatedAt time.TimeUpdatedAt time.Time
}func main() {// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情//loc 本地时区//想要正确的处理 time.Time 您需要带上 parseTime 参数dsn : root:roottcp(192.168.0.102:3306)/gorm_test?charsetutf8mb4parseTimeTruelocLocalnewLogger : logger.New(log.New(os.Stdout, \r\n, log.LstdFlags), // io writerlogger.Config{SlowThreshold: time.Second, // 慢SQL阈值LogLevel: logger.Info, // 日志级别IgnoreRecordNotFoundError: false,ParameterizedQueries: false, // 不要在SQL日志中包含参数Colorful: true, // 禁言彩色打印},)db, err : gorm.Open(mysql.Open(dsn), gorm.Config{Logger: newLogger,})if err ! nil {panic(err)}_ db.AutoMigrate(User{}) //此次应该有sql语句user : User{Name: bobby2,}//user.ID // 返回插入数据的主键//result.Error // 返回 error//result.RowsAffected // 返回插入记录的条数fmt.Println(user.ID)result : db.Create(user)fmt.Println(user.ID)fmt.Println(result.Error)fmt.Println(result.RowsAffected)//updates语句不会更新零值但update语句会更新//db.Model(User{ID: 1}).Update(Name, )//db.Model(User{ID: 1}).Updates(User{Name: })//解决仅更新非零值字段的方法有两种/**1 将string设置为*string2 使用sql的NULLxxx来结局*///empty : //db.Model(User{ID: 1}).Updates(User{Email: empty})}用指定的字段创建记录
创建记录并为指定字段赋值。
db.Select(Name, Age, CreatedAt).Create(user)
// INSERT INTO users (name,age,created_at) VALUES (jinzhu, 18, 2020-07-04 11:05:21.775)创建记录并忽略传递给 ‘Omit’ 的字段值
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)批量插入
要高效地插入大量记录请将切片传递给Create方法。GORM将生成一条SQL语句来插入所有数据并回填主键值钩子方法也将被调用。. 当记录可以分成多个批处理时它将开始一个 交易。
var users []User{{Name: jinzhu1}, {Name: jinzhu2}, {Name: jinzhu3}}
db.Create(users)for _, user : range users {user.ID // 1,2,3
}你可以在使用CreateInBatches创建时指定批处理大小例如:
var users []User{{Name: jinzhu_1}, ...., {Name: jinzhu_10000}}// batch size 100
db.CreateInBatches(users, 100)为什么不一次性提交所有的还要分批次 答sql语句是有长度限制!
在使用Upsert(插入更新)和Create With Associations(使用关联创建)时也支持批量插入 初始化GORM时使用CreateBatchSize选项所有INSERT在创建记录和关联时都将遵循此选项
db, err : gorm.Open(sqlite.Open(gorm.db), gorm.Config{CreateBatchSize: 1000,
})db : db.Session(gorm.Session{CreateBatchSize: 1000})users [5000]User{{Name: jinzhu, Pets: []Pet{pet1, pet2, pet3}}...}db.Create(users)
// INSERT INTO users xxx (5 batches)
// INSERT INTO pets xxx (15 batches)创建钩子
GORM允许用户定义钩子来实现前保存前创建后保存后创建。这些钩子方法将在创建记录时被调用有关生命周期的详细信息请参阅Hooks
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)根据 Map 创建
GORM支持从map[string]interface{}和[]map[string]interface{}创建例如:
db.Model(User{}).Create(map[string]interface{}{Name: jinzhu, Age: 18,
})// batch insert from []map[string]interface{}{}
db.Model(User{}).Create([]map[string]interface{}{{Name: jinzhu_1, Age: 18},{Name: jinzhu_2, Age: 20},
})当创建from map时钩子不会被调用关联不会被保存主键值不会被回填
关联创建—这个很像一对一
当创建一些具有关联的数据时如果它的关联值不是零值那么这些关联将被替换并且它的Hooks方法将被调用。
type CreditCard struct {gorm.ModelNumber stringUserID uint
}type User struct {gorm.ModelName stringCreditCard CreditCard
}db.Create(User{Name: jinzhu,CreditCard: CreditCard{Number: 411111111111}
})
// INSERT INTO users ...
// INSERT INTO credit_cards ...你可以使用Select, Omit跳过保存关联例如:
db.Omit(CreditCard).Create(user)
// skip all associations
db.Omit(clause.Associations).Create(user)查询
检索单个对象 GORM 提供了 First、Take、Last 方法以便从数据库中检索单个对象。当查询数据库时它添加了 LIMIT 1 条件且没有找到记录时它会返回 ErrRecordNotFound 错误
// 获取第一条记录主键升序
db.First(user)
// SELECT * FROM users ORDER BY id LIMIT 1;// 获取一条记录没有指定排序字段
db.Take(user)
// SELECT * FROM users LIMIT 1;// 获取最后一条记录主键降序
db.Last(user)
// SELECT * FROM users ORDER BY id DESC LIMIT 1;result : db.First(user)
result.RowsAffected // 返回找到的记录数
result.Error // returns error or nil// 检查 ErrRecordNotFound 错误没有找到数据
errors.Is(result.Error, gorm.ErrRecordNotFound)如果你想避免ErrRecordNotFound错误你可以使用Find比如db.Limit(1).Find(user)Find方法可以接受struct和slice的数据。 对单个对象使用Find而不带limitdb.Find(user)将会查询整个表并且只返回第一个对象这是性能不高并且不确定的。
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//通过first查询单个数据
var user User
db.First(user)//通过主键查询
//我们不能给user赋值
result : db.First(user, 2)if errors.Is(result.Error, gorm.ErrRecordNotFound) {fmt.Println(未找到)
}
fmt.Println(user.ID)var users []User
result1 : db.Find(users)
fmt.Println(总共记录, result1.RowsAffected)for _, user : range users {fmt.Println(user.ID)
}根据主键检索
如果主键是数字类型您可以使用 内联条件 来检索对象。 当使用字符串时需要额外的注意来避免SQL注入查看 Security 部分来了解详情。
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);//通过first查询单个数据var user Userdb.First(user)//通过主键查询//我们不能给user赋值result : db.First(user, 2)if errors.Is(result.Error, gorm.ErrRecordNotFound) {fmt.Println(未找到)}fmt.Println(user.ID)如果主键是字符串(例如像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;NOTE: 如果您使用 gorm 的特定字段类型例如 gorm.DeletedAt它将运行不同的查询来检索对象。
type User struct {ID string gorm:primarykey;size:16Name string gorm:size:24DeletedAt gorm.DeletedAt gorm:index
}var user User{ID: 15}
db.First(user)
// SELECT * FROM users WHERE users.id 15 AND users.deleted_at IS NULL ORDER BY users.id LIMIT 1检索全部对象
// Get all records
result : db.Find(users)
// SELECT * FROM users;result.RowsAffected // returns found records count, equals len(users)
result.Error // returns errorvar users []Userresult1 : db.Find(users)fmt.Println(总共记录, result1.RowsAffected)for _, user : range users {fmt.Println(user.ID)条件
String 条件
// 获取第一条匹配记录
db.Where(name ?, jinzhu).First(user)
// SELECT * FROM users WHERE name jinzhu ORDER BY id LIMIT 1;// 获取所有匹配的记录---这个获取的所有匹配的记录之外的
db.Where(name ?, jinzhu).Find(users)
// SELECT * FROM users WHERE name jinzhu;// INjinzhu或者jinzhu2
db.Where(name IN ?, []string{jinzhu, jinzhu 2}).Find(users)
// SELECT * FROM users WHERE name IN (jinzhu,jinzhu 2);// LIKE
db.Where(name LIKE ?, %jin%).Find(users)
// SELECT * FROM users WHERE name LIKE %jin%;// AND
db.Where(name ? AND age ?, jinzhu, 22).Find(users)
// SELECT * FROM users WHERE name jinzhu AND age 22;// Time
db.Where(updated_at ?, lastWeek).Find(users)
// SELECT * FROM users WHERE updated_at 2000-01-01 00:00:00;// BETWEEN
db.Where(created_at BETWEEN ? AND ?, lastWeek, today).Find(users)
// SELECT * FROM users WHERE created_at BETWEEN 2000-01-01 00:00:00 AND 2000-01-08 00:00:00;如果对象设置了主键条件查询将不会覆盖主键的值而是用 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。
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);当使用struct查询时GORM只会查询非零字段这意味着如果字段的值为0false或其他零值它将不会用于构建查询条件例如:
db.Where(User{Name: jinzhu, Age: 0}).Find(users)
// SELECT * FROM users WHERE name jinzhu;要在查询条件中包含零值您可以使用映射它将包括所有键值作为查询条件例如:
db.Where(map[string]interface{}{Name: jinzhu, Age: 0}).Find(users)
// SELECT * FROM users WHERE name jinzhu AND age 0;//通过where查询var user Userdb.Where(name ?, bobby1).First(user)var users []Userdb.Where(User{Name: bobby1}).Find(users) //这个才是查询所有的for _, user1 : range users {fmt.Println(user1.ID)}db.Where(name IN ?, []string{bobby1, bobby2}).Find(users)更新
保存所有字段 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;Save是一个组合功能。如果save value不包含主键它将执行Create否则将执行Update(包含所有字段)。
db.Save(User{Name: jinzhu, Age: 100})
// INSERT INTO users (name,age,birthday,update_at) VALUES (jinzhu,100,0000-00-00 00:00:00,0000-00-00 00:00:00)db.Save(User{ID: 1, Name: jinzhu, Age: 100})
// UPDATE users SET namejinzhu,age100,birthday0000-00-00 00:00:00,update_at0000-00-00 00:00:00 WHERE id 1更新单个列
当使用Update更新单个列时它需要有任何条件否则会引发错误ErrMissingWhereClause请查看Block Global Updates了解详细信息。当使用Model方法并且它的值有一个主值时主键将被用来构建条件例如:
// Update with conditions
db.Model(User{}).Where(active ?, true).Update(name, hello)
// UPDATE users SET namehello, updated_at2013-11-17 21:34:10 WHERE activetrue;// Users ID is 111:
db.Model(user).Update(name, hello)
// UPDATE users SET namehello, updated_at2013-11-17 21:34:10 WHERE id111;// Update with conditions and model value
db.Model(user).Where(active ?, true).Update(name, hello)
// UPDATE users SET namehello, updated_at2013-11-17 21:34:10 WHERE id111 AND activetrue;更新多列
Updates支持使用struct或map[string]接口{}进行更新当使用struct进行更新时默认情况下只更新非零字段
// Update attributes with struct, will only update non-zero fields
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;// Update attributes with 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;当使用struct进行更新时GORM只会更新非零字段。您可能希望使用map来更新属性或者使用Select来指定要更新的字段
更新选定字段
如果要更新选定的字段或在更新时忽略某些字段可以使用Select, Omit
// Select with Map
// Users ID is 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;// Select with Struct (select zero value fields)
db.Model(user).Select(Name, Age).Updates(User{Name: new_name, Age: 0})
// UPDATE users SET namenew_name, age0 WHERE id111;// Select all fields (select all fields include zero value fields)
db.Model(user).Select(*).Updates(User{Name: jinzhu, Role: admin, Age: 0})// Select all fields but omit Role (select all fields include zero value fields)
db.Model(user).Select(*).Omit(Role).Updates(User{Name: jinzhu, Role: admin, Age: 0})更新 Hook
GORM允许钩子beforeave, BeforeUpdate, AfterSave, AfterUpdate。这些方法将在更新记录时调用详情请参考Hooks
func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {if u.Role admin {return errors.New(admin user not allowed to update)}return
}批量更新
如果我们没有使用Model指定具有主键值的记录GORM将执行批处理更新
// Update with struct
db.Model(User{}).Where(role ?, admin).Updates(User{Name: hello, Age: 18})
// UPDATE users SET namehello, age18 WHERE role admin;// Update with map
db.Table(users).Where(id IN ?, []int{10, 11}).Updates(map[string]interface{}{name: hello, age: 18})
// UPDATE users SET namehello, age18 WHERE id IN (10, 11);阻止全局更新
如果你执行一个批处理更新没有任何条件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更新的记录数
获取受更新影响的行数
// Get updated records count with RowsAffected
result : db.Model(User{}).Where(role ?, admin).Updates(User{Name: hello, Age: 18})
// UPDATE users SET namehello, age18 WHERE role admin;result.RowsAffected // returns updated records count
result.Error // returns updating error删除
删除一条记录 删除一条记录时删除对象需要指定主键否则会触发 批量删除例如
// Email 的 ID 是 10
db.Delete(email)
// DELETE from emails where id 10;// 带额外条件的删除
db.Where(name ?, jinzhu).Delete(email)
// DELETE from emails where id 10 AND name jinzhu;根据主键删除
GORM 允许通过主键(可以是复合主键)和内联条件来删除对象它可以使用数字如以下例子。也可以使用字符串——译者注。查看 查询-内联条件Query Inline Conditions 了解详情。
db.Delete(User{}, 10)
// DELETE FROM users WHERE id 10;db.Delete(User{}, 10)
// DELETE FROM users WHERE id 10;db.Delete(users, []int{1,2,3})
// DELETE FROM users WHERE id IN (1,2,3);钩子函数
对于删除操作GORM 支持 BeforeDelete、AfterDelete Hook在删除记录时会调用这些方法查看 Hook 获取详情
func (u *User) BeforeDelete(tx *gorm.DB) (err error) {if u.Role admin {return errors.New(admin user not allowed to delete)}return
}批量删除
如果指定的值不包括主属性那么 GORM 会执行批量删除它将删除所有匹配的记录
db.Where(email LIKE ?, %jinzhu%).Delete(Email{})
// DELETE from emails where email LIKE %jinzhu%;db.Delete(Email{}, email LIKE ?, %jinzhu%)
// DELETE from emails where email LIKE %jinzhu%;可以将一个主键切片传递给Delete 方法以便更高效的删除数据量大的记录
var users []User{{ID: 1}, {ID: 2}, {ID: 3}}
db.Delete(users)
// DELETE FROM users WHERE id IN (1,2,3);db.Delete(users, name LIKE ?, %jinzhu%)
// DELETE FROM users WHERE name LIKE %jinzhu% AND id IN (1,2,3); 阻止全局删除
当你试图执行不带任何条件的批量删除时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返回删除行的数据
返回被删除的数据仅当数据库支持回写功能时才能正常运行如下例
// 回写所有的列
var users []User
DB.Clauses(clause.Returning{}).Where(role ?, admin).Delete(users)
// DELETE FROM users WHERE role admin RETURNING *
// users []User{{ID: 1, Name: jinzhu, Role: admin, Salary: 100}, {ID: 2, Name: jinzhu.2, Role: admin, Salary: 1000}}// 回写指定的列
DB.Clauses(clause.Returning{Columns: []clause.Column{{Name: name}, {Name: salary}}}).Where(role ?, admin).Delete(users)
// DELETE FROM users WHERE role admin RETURNING name, salary
// users []User{{ID: 0, Name: jinzhu, Role: , Salary: 100}, {ID: 0, Name: jinzhu.2, Role: , Salary: 1000}}软删除
如果你的模型包含了 gorm.DeletedAt字段该字段也被包含在gorm.Model中那么该模型将会自动获得软删除的能力 当调用Delete时GORM并不会从数据库中删除该记录而是将该记录的DeleteAt设置为当前时间而后的一般查询方法将无法查找到此条记录。
// users ID is 111
db.Delete(user)
// UPDATE users SET deleted_at2013-10-29 10:23 WHERE id 111;// Batch Delete
db.Where(age ?, 20).Delete(User{})
// UPDATE users SET deleted_at2013-10-29 10:23 WHERE age 20;// Soft deleted records will be ignored when querying
db.Where(age 20).Find(user)
// SELECT * FROM users WHERE age 20 AND deleted_at IS NULL;如果你并不想嵌套gorm.Model你也可以像下方例子那样开启软删除特性
type User struct {ID intDeleted gorm.DeletedAtName string
}查找被软删除的记录
你可以使用Unscoped来查询到被软删除的记录
db.Unscoped().Where(age 20).Find(users)
// SELECT * FROM users WHERE age 20;永久删除
你可以使用 Unscoped来永久删除匹配的记录
db.Unscoped().Delete(order)
// DELETE FROM orders WHERE id10;删除标志
默认情况下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;你同样可以指定使用毫秒 milli或纳秒 nano作为值如下例
type User struct {ID uintName stringDeletedAt soft_delete.DeletedAt gorm:softDelete:milli// DeletedAt soft_delete.DeletedAt gorm:softDelete:nano
}// 查询
SELECT * FROM users WHERE deleted_at 0;// 软删除
UPDATE users SET deleted_at /* current unix milli second or nano 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;Belongs To
belongs to 会与另一个模型建立了一对一的连接。 这种模型的每一个实例都“属于”另一个模型的一个实例。 例如您的应用包含 user 和 company并且每个 user 能且只能被分配给一个 company。下面的类型就表示这种关系。 注意在 User 对象中有一个和 Company 一样的 CompanyID。 默认情况下 CompanyID 被隐含地用来在 User 和 Company 之间创建一个外键关系 因此必须包含在 User 结构体中才能填充 Company 内部结构体。
// User 属于 CompanyCompanyID 是外键
type User struct {gorm.ModelName stringCompanyID intCompany Company
}type Company struct {ID intName string
}重写外键
要定义一个 belongs to 关系数据库的表中必须存在外键。默认情况下外键的名字使用拥有者的类型名称加上表的主键的字段名字 例如定义一个User实体属于Company实体那么外键的名字一般使用CompanyID。 GORM同时提供自定义外键名字的方式如下例所示。
type User struct {gorm.ModelName stringCompanyRefer intCompany Company gorm:foreignKey:CompanyRefer// 使用 CompanyRefer 作为外键
}type Company struct {ID intName string
}重写引用
对于 belongs to 关系GORM 通常使用数据库表主表拥有者的主键值作为外键参考。 正如上面的例子我们使用主表Company中的主键字段ID作为外键的参考值。 如果设置了User实体属于Company实体那么GORM会自动把Company中的ID属性保存到User的CompanyID属性中。 同样的您也可以使用标签 references 来更改它例如
type User struct {gorm.ModelName stringCompanyID stringCompany Company gorm:references:Code // 使用 Code 作为引用
}type Company struct {ID intCode stringName string
}NOTE 如果外键名恰好在拥有者类型中存在GORM 通常会错误的认为它是 has one 关系。我们需要在 belongs to 关系中指定 references
type User struct {gorm.ModelName stringCompanyID stringCompany Company gorm:references:CompanyID // 使用 Company.CompanyID 作为引用
}type Company struct {CompanyID intCode stringName string
}package mainimport (gorm.io/driver/mysqlgorm.io/gormgorm.io/gorm/loggerlogostime
)type User struct {gorm.ModelName stringCompanyID int //数据库中存储的字段 sql使用它Company Company
}type Company struct {ID intName string
}func main() {// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情//loc 本地时区//想要正确的处理 time.Time 您需要带上 parseTime 参数dsn : root:roottcp(192.168.0.102:3306)/gorm_test?charsetutf8mb4parseTimeTruelocLocalnewLogger : logger.New(log.New(os.Stdout, \r\n, log.LstdFlags), // io writerlogger.Config{SlowThreshold: time.Second, // 慢SQL阈值LogLevel: logger.Info, // 日志级别IgnoreRecordNotFoundError: false,ParameterizedQueries: false, // 不要在SQL日志中包含参数Colorful: true, // 禁言彩色打印},)db, err : gorm.Open(mysql.Open(dsn), gorm.Config{Logger: newLogger,})if err ! nil {panic(err)}//db.AutoMigrate(User{}) //新建了user表和company表并且设置外键//db.Create(User{// Name: bobby,// Company: Company{// Name: chengpeng,// },//})//解决外键存在的问题db.Create(User{Name: bobby2,Company: Company{ID: 1,},})
}Belongs to 的 CRUD
查看 关联模式 获取 belongs to 相关的用法
预加载
GORM 可以通过 Preload、Joins 预加载 belongs to 关联的记录查看 预加载 获取详情
外键约束
你可以通过 constraint 标签配置 OnUpdate、OnDelete 实现外键约束在使用 GORM 进行迁移时它会被创建例如
type User struct {gorm.ModelName stringCompanyID intCompany Company gorm:constraint:OnUpdate:CASCADE,OnDelete:SET NULL;
}type Company struct {ID intName string
}var user User
//Preload
//db.Preload(Company).First(user)
db.Joins(Company).First(user)
fmt.Println(user)Has Many
has many 与另一个模型建立了一对多的连接。 不同于 has one拥有者可以有零或多个关联模型。
例如您的应用包含 user 和 credit card 模型且每个 user 可以有多张 credit card。
声明
// User 有多张 CreditCardUserID 是外键
type User struct {gorm.ModelCreditCards []CreditCard
}type CreditCard struct {gorm.ModelNumber stringUserID uint
}检索
// 检索用户列表并预加载信用卡
func GetAll(db *gorm.DB) ([]User, error) {var users []Usererr : db.Model(User{}).Preload(CreditCards).Find(users).Errorreturn users, err
}重写外键
要定义 has many 关系同样必须存在外键。 默认的外键名是拥有者的类型名加上其主键字段名 例如要定义一个属于 User 的模型则其外键应该是 UserID。 此外想要使用另一个字段作为外键您可以使用 foreignKey 标签自定义它
type User struct {gorm.ModelCreditCards []CreditCard gorm:foreignKey:UserRefer
}type CreditCard struct {gorm.ModelNumber stringUserRefer uint
}重写引用
GORM 通常使用拥有者的主键作为外键的值。 对于上面的例子它是 User 的 ID 字段。 为 user 添加 credit card 时GORM 会将 user 的 ID 字段保存到 credit card 的 UserID 字段。 同样的您也可以使用标签 references 来更改它例如
type User struct {gorm.ModelMemberNumber stringCreditCards []CreditCard gorm:foreignKey:UserNumber;references:MemberNumber
}type CreditCard struct {gorm.ModelNumber stringUserNumber string
}多态关联
GORM 为 has one 和 has many 提供了多态关联支持它会将拥有者实体的表名、主键都保存到多态类型的字段中。
type Dog struct {ID intName stringToys []Toy gorm:polymorphic:Owner;
}type Toy struct {ID intName stringOwnerID intOwnerType string
}db.Create(Dog{Name: dog1, Toys: []Toy{{Name: toy1}, {Name: toy2}}})
// INSERT INTO dogs (name) VALUES (dog1)
// INSERT INTO toys (name,owner_id,owner_type) VALUES (toy1,1,dogs), (toy2,1,dogs)您可以使用标签 polymorphicValue 来更改多态类型的值例如
type Dog struct {ID intName stringToys []Toy gorm:polymorphic:Owner;polymorphicValue:master
}type Toy struct {ID intName stringOwnerID intOwnerType string
}db.Create(Dog{Name: dog1, Toys: []Toy{{Name: toy1}, {Name: toy2}}})
// INSERT INTO dogs (name) VALUES (dog1)
// INSERT INTO toys (name,owner_id,owner_type) VALUES (toy1,1,master), (toy2,1,master)Has Many 的 CURD
查看 关联模式 获取 has many 相关的用法
预加载
GORM 可以通过 Preload 预加载 has many 关联的记录查看 预加载 获取详情
自引用 Has Many
type User struct {gorm.ModelName stringManagerID *uintTeam []User gorm:foreignkey:ManagerID
}外键约束
你可以通过为标签 constraint 配置 OnUpdate、OnDelete 实现外键约束在使用 GORM 进行迁移时它会被创建例如
type User struct {gorm.ModelCreditCards []CreditCard gorm:constraint:OnUpdate:CASCADE,OnDelete:SET NULL;
}type CreditCard struct {gorm.ModelNumber stringUserID uint
}你也可以在删除记录时通过 Select 来删除 has many 关联的记录查看 Delete with Select 获取详情
package mainimport (fmtgorm.io/driver/mysqlgorm.io/gormgorm.io/gorm/loggerlogostime
)// User 有多张 CreditCardUserID 是外键
type User struct {gorm.ModelCreditCards []CreditCard gorm:foreignKey:UserID
}type CreditCard struct {gorm.ModelNumber stringUserID uint
}func main() {// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情//loc 本地时区//想要正确的处理 time.Time 您需要带上 parseTime 参数dsn : root:roottcp(192.168.0.102:3306)/gorm_test?charsetutf8mb4parseTimeTruelocLocalnewLogger : logger.New(log.New(os.Stdout, \r\n, log.LstdFlags), // io writerlogger.Config{SlowThreshold: time.Second, // 慢SQL阈值LogLevel: logger.Info, // 日志级别IgnoreRecordNotFoundError: false,ParameterizedQueries: false, // 不要在SQL日志中包含参数Colorful: true, // 禁言彩色打印},)db, err : gorm.Open(mysql.Open(dsn), gorm.Config{Logger: newLogger,})if err ! nil {panic(err)}//db.AutoMigrate(User{}) //如果一个一个创建就会发现没有外键//db.AutoMigrate(CreditCard{})//db.AutoMigrate(User{}, CreditCard{}) //这样创建就会有外键//user : User{}//db.Create(user)//db.Create(CreditCard{// Number: 123,// UserID: 1,//})////db.Create(CreditCard{// Number: 1234,// UserID: 1,//})var user Userdb.Preload(CreditCards).First(user)for _, card : range user.CreditCards {fmt.Println(card.Number)}
}在大型的系统中不建议使用外键约束外键约束也有很大的优点:数据的完整性 外键约束会让你的数据很完整即使是业务代码有些人考虑的不严谨也不会造成数据不一致 在大型的系统高并发的系统重一般不使用外键约束自己在业务层面保证数据的一致性
Many To Many
Many to Many 会在两个 model 中添加一张连接表。 例如您的应用包含了 user 和 language且一个 user 可以说多种 language多个 user 也可以说一种 language。
// User 拥有并属于多种 languageuser_languages 是连接表
type User struct {gorm.ModelLanguages []Language gorm:many2many:user_languages;
}type Language struct {gorm.ModelName string
}当使用 GORM 的 AutoMigrate 为 User 创建表时GORM 会自动创建连接表
反向引用
声明
// User 拥有并属于多种 languageuser_languages 是连接表
type User struct {gorm.ModelLanguages []*Language gorm:many2many:user_languages;
}type Language struct {gorm.ModelName stringUsers []*User gorm:many2many:user_languages;
}检索
// 检索 User 列表并预加载 Language
func GetAllUsers(db *gorm.DB) ([]User, error) {var users []Usererr : db.Model(User{}).Preload(Languages).Find(users).Errorreturn users, err
}// 检索 Language 列表并预加载 User
func GetAllLanguages(db *gorm.DB) ([]Language, error) {var languages []Languageerr : db.Model(Language{}).Preload(Users).Find(languages).Errorreturn languages, err
}重写外键
对于 many2many 关系连接表会同时拥有两个模型的外键例如
type User struct {gorm.ModelLanguages []Language gorm:many2many:user_languages;
}type Language struct {gorm.ModelName string
}// 连接表user_languages
// foreign key: user_id, reference: users.id
// foreign key: language_id, reference: languages.id若要重写它们可以使用标签 foreignKey、references、joinforeignKey、joinReferences。当然您不需要使用全部的标签你可以仅使用其中的一个重写部分的外键、引用。
type User struct {gorm.ModelProfiles []Profile gorm:many2many:user_profiles;foreignKey:Refer;joinForeignKey:UserReferID;References:UserRefer;joinReferences:ProfileReferRefer uint gorm:index:,unique
}type Profile struct {gorm.ModelName stringUserRefer uint gorm:index:,unique
}// 会创建连接表user_profiles
// foreign key: user_refer_id, reference: users.refer
// foreign key: profile_refer, reference: profiles.user_refer注意 某些数据库只允许在唯一索引字段上创建外键如果您在迁移时会创建外键则需要指定 unique index 标签。
自引用 Many2Many
自引用 many2many 关系
type User struct {gorm.ModelFriends []*User gorm:many2many:user_friends
}// 会创建连接表user_friends
// foreign key: user_id, reference: users.id
// foreign key: friend_id, reference: users.id预加载
GORM 可以通过 Preload 预加载 has many 关联的记录查看 预加载 获取详情
Many2Many 的 CURD
查看 关联模式 获取 many2many 相关的用法
自定义连接表
JoinTable可以是一个全功能的模型像有软删除钩子支持和更多的字段你可以设置它与SetupJoinTable例如: 注意 自定义连接表要求外键是复合主键或复合唯一索引
type Person struct {ID intName stringAddresses []Address gorm:many2many:person_addressses;
}type Address struct {ID uintName string
}type PersonAddress struct {PersonID int gorm:primaryKeyAddressID int gorm:primaryKeyCreatedAt time.TimeDeletedAt gorm.DeletedAt
}func (PersonAddress) BeforeCreate(db *gorm.DB) error {// ...
}// 修改 Person 的 Addresses 字段的连接表为 PersonAddress
// PersonAddress 必须定义好所需的外键否则会报错
err : db.SetupJoinTable(Person{}, Addresses, PersonAddress{})外键约束
你可以通过为标签 constraint 配置 OnUpdate、OnDelete 实现外键约束在使用 GORM 进行迁移时它会被创建例如
type User struct {gorm.ModelLanguages []Language gorm:many2many:user_speaks;
}type Language struct {Code string gorm:primarykeyName string
}// CREATE TABLE user_speaks (user_id integer,language_code text,PRIMARY KEY (user_id,language_code),CONSTRAINT fk_user_speaks_user你也可以在删除记录时通过 Select 来删除 many2many 关系的记录查看 Delete with Select 获取详情
复合外键
如果您的模型使用了 复合主键GORM 会默认启用复合外键。
您也可以覆盖默认的外键、指定多个外键只需用逗号分隔那些键名例如
type Tag struct {ID uint gorm:primaryKeyLocale string gorm:primaryKeyValue string
}type Blog struct {ID uint gorm:primaryKeyLocale string gorm:primaryKeySubject stringBody stringTags []Tag gorm:many2many:blog_tags;LocaleTags []Tag gorm:many2many:locale_blog_tags;ForeignKey:id,locale;References:idSharedTags []Tag gorm:many2many:shared_blog_tags;ForeignKey:id;References:id
}// 连接表blog_tags
// foreign key: blog_id, reference: blogs.id
// foreign key: blog_locale, reference: blogs.locale
// foreign key: tag_id, reference: tags.id
// foreign key: tag_locale, reference: tags.locale// 连接表locale_blog_tags
// foreign key: blog_id, reference: blogs.id
// foreign key: blog_locale, reference: blogs.locale
// foreign key: tag_id, reference: tags.id// 连接表shared_blog_tags
// foreign key: blog_id, reference: blogs.id
// foreign key: tag_id, reference: tags.idpackage mainimport (fmtgorm.io/driver/mysqlgorm.io/gormgorm.io/gorm/loggerlogostime
)type User struct {gorm.ModelLanguages []Language gorm:many2many:user_languages;
}type Language struct {gorm.ModelName string
}func main() {// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情//loc 本地时区//想要正确的处理 time.Time 您需要带上 parseTime 参数dsn : root:roottcp(192.168.0.102:3306)/gorm_test?charsetutf8mb4parseTimeTruelocLocalnewLogger : logger.New(log.New(os.Stdout, \r\n, log.LstdFlags), // io writerlogger.Config{SlowThreshold: time.Second, // 慢SQL阈值LogLevel: logger.Info, // 日志级别IgnoreRecordNotFoundError: false,ParameterizedQueries: false, // 不要在SQL日志中包含参数Colorful: true, // 禁言彩色打印},)db, err : gorm.Open(mysql.Open(dsn), gorm.Config{Logger: newLogger,})if err ! nil {panic(err)}//db.AutoMigrate(User{})//插入//languages : []Language{}//languages append(languages, Language{Name: go})//languages append(languages, Language{Name: java})//user : User{//// Languages: languages,//}////db.Create(user)//获取数据--第一种//var user User//db.Preload(Languages).First(user)//for _, language : range user.Languages {// fmt.Println(language.Name)//}//如果我们已经取出一个用户来了但是这个用户我们之前没有使用preload来加载对应的Languages//不是说用户有language我们就一定要取出来// 开始关联模式//查找关联--第二种方法var user Userdb.First(user)var laguages []Language_ db.Model(user).Association(Languages).Find(laguages)for _, laguage : range laguages {fmt.Println(laguage.Name)}fmt.Println(user.ID)}我们自己定义表面是什么 同一的给所有的表面加上前缀 NamingStrategy和TableName不能同时配置
package mainimport (gorm.io/driver/mysqlgorm.io/gormgorm.io/gorm/loggergorm.io/gorm/schemalogostime
)//type Language1 struct {
// gorm.Model
// Name string
//}type Language2 struct {Name stringAddTime time.Time //每个记录创建的时候自动加上当前加入到AddTime中 不加BeforeCreate这个方法就会报错//也可以加这样加//AddTime1 sql.NullTime
}func (l *Language2) BeforeCreate(tx *gorm.DB) (err error) {l.AddTime time.Now()return
}//在数据默认是加一个默认值// TableName 在gorm中可以通过给某一个struct添加TableName方法自定义表面
// 自定义表名
//func (Language1) TableName() string {
// return my_language
//}// 同一个表名加一个前缀
func main() {// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情//loc 本地时区//想要正确的处理 time.Time 您需要带上 parseTime 参数dsn : root:roottcp(192.168.0.102:3306)/gorm_test?charsetutf8mb4parseTimeTruelocLocal//NamingStrategy和TableName不能同时配置newLogger : logger.New(log.New(os.Stdout, \r\n, log.LstdFlags), // io writerlogger.Config{SlowThreshold: time.Second, // 慢SQL阈值LogLevel: logger.Info, // 日志级别IgnoreRecordNotFoundError: false,ParameterizedQueries: false, // 不要在SQL日志中包含参数Colorful: true, // 禁言彩色打印},)db, err : gorm.Open(mysql.Open(dsn), gorm.Config{NamingStrategy: schema.NamingStrategy{TablePrefix: chengpeng_,},Logger: newLogger,})if err ! nil {panic(err)}db.AutoMigrate(Language2{})db.Create(Language2{Name: Python})
}