Gorm

因为没有深入了解过Gorm,了解一下

配置

之前连接有个细节没注意

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
dsn := "user:password@tcp(127.0.0.1:3307)/shortURL?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.New(mysql.Config{
DSN: dsn,
}),
&gorm.Config{
SkipDefaultTransaction: false, //跳过事务控制,但是关掉后不保证数据一致性
NamingStrategy: schema.NamingStrategy{
TablePrefix: "test_", // 表名前缀,`User` 的表名应该是 `t_users`
SingularTable: false, // 使用单数表名,启用该选项后,`User` 的表名应该是 `t_user`
},
// Logger: 很重要,可以自定义
//NowFunc: //自创一个时间,用自己的时间方法
DisableForeignKeyConstraintWhenMigrating: true, // 禁用物理外键,更多使用逻辑外键,可以提高数据库运行的速度
})
if err != nil {
log.Println(err)
}

mysql.New的书写,对于mysql的配置也可以用config去书写

对于gorm的书写也可以配置,这里举例的是比较常见的几个

更多:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// mysql.Config{}
type Config struct {
DriverName string
ServerVersion string
DSN string
Conn gorm.ConnPool
SkipInitializeWithVersion bool
DefaultStringSize uint
DefaultDatetimePrecision *int
DisableWithReturning bool
DisableDatetimePrecision bool
DontSupportRenameIndex bool
DontSupportRenameColumn bool
DontSupportForShareClause bool
DontSupportNullAsDefaultValue bool
}
// Gorm.Config{}
type Config struct {
// GORM perform single create, update, delete operations in transactions by default to ensure database data integrity
// You can disable it by setting `SkipDefaultTransaction` to true 关闭事务
SkipDefaultTransaction bool
// NamingStrategy tables, columns naming strategy 取名
NamingStrategy schema.Namer
// FullSaveAssociations full save associations 全部保存关联操作
FullSaveAssociations bool
// Logger 数据库日志
Logger logger.Interface
// NowFunc the function to be used when creating a new timestamp 时间表示
NowFunc func() time.Time
// DryRun generate sql without execute
DryRun bool
// PrepareStmt executes the given query in cached statement
PrepareStmt bool
// DisableAutomaticPing
DisableAutomaticPing bool
// DisableForeignKeyConstraintWhenMigrating
DisableForeignKeyConstraintWhenMigrating bool 禁止物理外键关联
// IgnoreRelationshipsWhenMigrating 忽略关系
IgnoreRelationshipsWhenMigrating bool
// DisableNestedTransaction disable nested transaction
DisableNestedTransaction bool
// AllowGlobalUpdate allow global update
AllowGlobalUpdate bool
// QueryFields executes the SQL query with all fields of the table
QueryFields bool
// CreateBatchSize default create batch size
CreateBatchSize int

// ClauseBuilders clause builder
ClauseBuilders map[string]clause.ClauseBuilder
// ConnPool db conn pool
ConnPool ConnPool
// Dialector database dialector
Dialector
// Plugins registered plugins
Plugins map[string]Plugin

callbacks *callbacks
cacheStore *sync.Map
}
// 有些没解释的是因为我也还没学到

迁移

1
2
3
4
5
6
// 自动整合
db.AutoMigrate()

// 手动整合,可操作性更强
m := db.Migrate()
m.function() //function表示各种各样的方法,m是Interface的类型

Migrator - interface{}

1
2
3
4
5
6
// Table
CreateTable(dst ...interface{}) error
DropTable(dst ...interface{}) error
HasTable(dst interface{}) bool
RenameTable(oldName, newName interface{}) error
GetTables() (tableList []string, err error)
1
2
3
4
5
6
7
8
9
// column 
// 需要注意的是,如果要修改某个列名,列名一般是xx_xx,所以命名的时候要规范
AddColumn(dst interface{}, field string) error
DropColumn(dst interface{}, field string) error
AlterColumn(dst interface{}, field string) error
MigrateColumn(dst interface{}, field *schema.Field, columnType ColumnType) error
HasColumn(dst interface{}, field string) bool
RenameColumn(dst interface{}, oldName, field string) error
ColumnTypes(dst interface{}) ([]ColumnType, error)
1
2
3
4
5
6
7
8
9
10
11
12
// 一般标签中呈现 	
// constaint 约束
CreateConstraint(dst interface{}, name string) error
DropConstraint(dst interface{}, name string) error
HasConstraint(dst interface{}, name string) bool

// Indexes 索引
CreateIndex(dst interface{}, name string) error
DropIndex(dst interface{}, name string) error
HasIndex(dst interface{}, name string) bool
RenameIndex(dst interface{}, oldName, newName string) error
GetIndexes(dst interface{}) ([]Index, error)

外键

其实我本来是想随便看看约束的,然后就看到外键,然后想着对外键的理解不够充分,所以就看了一些东西

外键约束—外键详解

外键是表的一个字段,不是本表的主键,但对应另一个表的主键。

外键本身只是一个普通字段,但是他跟约束结合在一起就不普通了

如果外键太多,就可以生成一个外键表

作用:

  1. 引用完整性:外键约束确保子表中的数据引用在父表中有对应的主键值。如果尝试在子表中插入不存在的父表主键值,MySQL将拒绝该操作。
  2. 级联操作:当父表中的主键值被修改或删除时,MySQL可以根据外键约束的设置自动更新或删除子表中的相关数据。
  3. 防止孤立记录:通过外键约束,可以防止在子表中存在与父表中没有关联的孤立记录。
  4. 提高查询性能:外键约束可以帮助数据库优化器更高效地执行查询操作,因为它可以快速识别哪些记录是有效的或无效的。
    如何使用外键约束:

外键+约束:外键约束

​ 您可以选择指定外键约束的操作,以定义在引用表或被引用表中执行DML操作时的行为。常见的外键约束操作包括:

  • ON DELETE:定义在被引用表中执行删除操作时的行为,常见的选项包括CASCADE(级联删除)、SET NULL(设置为空)、SET DEFAULT(设置为默认值)等。
  • ON UPDATE:定义在被引用表中执行更新操作时的行为,常见的选项包括CASCADESET NULLSET DEFAULT等。

4. 外键约束的类型

MySQL支持多种外键约束的类型,包括以下几种常见类型:

4.1 单列外键约束

单列外键约束是指外键关联的字段只有一个,它通常用于建立单一字段的关联关系。例如,可以在一个订单表中使用客户ID作为外键,与客户表中的客户ID关联,以表示订单与客户之间的关联关系。

4.2 复合外键约束

复合外键约束是指外键关联的字段有多个,它用于建立多个字段的组合关联关系。例如,可以在一个员工表中使用部门ID和经理ID作为外键,与部门表中的部门ID和员工ID关联,以表示员工与部门和经理之间的关联关系。

4.3 自引用外键约束

自引用外键约束是指一个表中的外键关联到该表中的另一个字段,通常用于表示层次结构关系。例如,可以在一个员工表中使用上级员工ID作为外键,关联到员工表中的员工ID,以表示员工与其上级员工之间的关联关系。

4.4 级联外键约束

级联外键约束是指在外键操作时会自动执行相应的级联操作。常见的级联操作包括:

  • CASCADE:级联删除或更新,表示在被引用表中执行删除或更新操作时,会自动删除或更新引用表中的相关记录。
  • SET NULL:表示在被引用表中执行删除操作时,将引用表中的外键字段设置为NULL
  • SET DEFAULT:表示在被引用表中执行删除操作时,将引用表中的外键字段设置为默认值。

级联外键中ON DELETE、ON UPDATE表示事件触发时的动作,可设置值为:

  • CASCADE,更新或者删除父表记录时,子表中的相应记录同步更新或者删除。由级联更新或者删除导致的子表记录修改,不会触发子表的触发器执行。
  • SET NULL,更新或者删除父表记录时,子表中的相应记录字段设置为NULL,前提是子表中相应字段不能定义为NOT NULL。
  • RESTRICT,有外键关系约束时,拒绝父表记录的更新和删除操作。
  • NO ACTION,无动作,实际功能与RESTRICT相同。
  • SET DEFAULT,仅仅解析器能识别,实际功能未实现

(级联外键约束可以联想一下奖学金V4结构体操作)

外键的性能

外键的设立,必定是设立索引的

  • 索引维护: 外键约束通常需要创建索引来加速引用表的查找操作。这些索引需要维护,因此在插入、更新和删除操作时会导致额外的开销。
  • 级联操作: 当使用级联操作时,数据库需要执行额外的删除或更新操作,这可能会导致性能下降。
  • 锁定: 外键约束可能导致表级别或行级别的锁定,这会影响并发性能。

索引

小林Coding

顺便把索引也夯实一下

索引是一种数据结构,主要用于查询而不是更新,可以类似看作书中的目录,让我们不用一页一页地去找需要的内容,这是一种用空间换时间的方法,因此使用索引的时候需要考虑空间的原因(不是每个字段都要加上索引)

索引的种类略过,以后再说

什么时候需要 / 不需要创建索引?

索引最大的好处是提高查询速度,但是索引也是有缺点的,比如:

  • 需要占用物理空间,数量越大,占用空间越大;
  • 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增大;
  • 会降低表的增删改的效率,因为每次增删改索引,B+ 树为了维护索引有序性,都需要进行动态维护。

所以,索引不是万能钥匙,它也是根据场景来使用的。

什么时候适用索引?

  • 字段有唯一性限制的,比如商品编码;
  • 经常用于 WHERE 查询条件的字段,这样能够提高整个表的查询速度,如果查询条件不是一个字段,可以建立联合索引。
  • 经常用于 GROUP BYORDER BY 的字段,这样在查询的时候就不需要再去做一次排序了,因为我们都已经知道了建立索引之后在 B+Tree 中的记录都是排序好的。

什么时候不需要创建索引?

  • WHERE 条件,GROUP BYORDER BY 里用不到的字段,索引的价值是快速定位,如果起不到定位的字段通常是不需要创建索引的,因为索引是会占用物理空间的。
  • 字段中存在大量重复数据,不需要创建索引,比如性别字段,只有男女,如果数据库表中,男女的记录分布均匀,那么无论搜索哪个值都可能得到一半的数据。在这些情况下,还不如不要索引,因为 MySQL 还有一个查询优化器,查询优化器发现某个值出现在表的数据行中的百分比很高的时候,它一般会忽略索引,进行全表扫描。
  • 表数据太少的时候,不需要创建索引;
  • 经常更新的字段不用创建索引,比如不要对电商项目的用户余额建立索引,因为索引字段频繁修改,由于要维护 B+Tree的有序性,那么就需要频繁的重建索引,这个过程是会影响数据库性能的。

标签

gorm:"xxx:not null; ..."

标签名 说明
column 指定 db 列名
type 列数据类型,推荐使用兼容性好的通用类型,例如:所有数据库都支持 bool、int、uint、float、string、time、bytes 并且可以和其他标签一起使用,例如:、, … 像 这样指定数据库数据类型也是支持的。在使用指定数据库数据类型时,它需要是完整的数据库数据类型,如:not null``size``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 根据参数创建索引,多个字段使用相同的名称则创建复合索引,查看 索引 获取详情
uniqueIndex 与 相同,但创建的是唯一索引index
check 创建检查约束,例如 ,查看 约束 获取详情check:age > 13
<- 设置字段写入的权限, 只创建、 只更新、 无写入权限、 创建和更新权限<-:create``<-:update``<-:false``<-
-> 设置字段读的权限, 无读权限->:false
- 忽略该字段, 表示无读写, 表示无迁移权限, 表示无读写迁移权限-``-:migration``-:all

关于 embedded

1
2
3
4
5
6
7
8
9
10
11
12
13
14
type Base struct {
ID uint
Name string
}
// 如果是匿名结构体可以直接写
type Student1 struct{
Base
Email string
}
// 如果是有名字的需要加embedded
type Student2 struct{
base Base `gorm:"embedded"`
Email string
}

连接池(初窥)

这个是看NX博客,有点没看懂说实话 Golang 侧数据库连接池原理和参数调优

数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。

算了,不看了,有兴趣自己看链接把

总结

我也没想写这么多…..