vault backup: 2026-04-28 20:56:51

This commit is contained in:
2026-04-28 20:56:51 +08:00
parent 39aaa384ba
commit 0cc894a3cb
14 changed files with 1566 additions and 440 deletions
+19 -20
View File
@@ -166,26 +166,25 @@ type Ticket struct {
> [!note] GORMDataType 的作用范围
> 它只在**建表(AutoMigrate)**时生效,不影响运行时读写行为。也就是说,GORM 会用这个类型创建列,但数据的序列化和反序列化仍由 `database/sql` 的标准处理完成。
## 结合 Use 注册全局解析器
## 全局类型解析器(Resolver)
对于不想在每个 struct 上实现接口的场景(比如第三方类型的扩展),可以用 `RegisterResolve`:
GORM v1.25+ 引入了 Resolver API,可以在不修改类型定义的前提下注册自定义解析:
```go
// 为 net.IP 类型注册 GORM 解析逻辑
db.Use(clause.OnConflict{}, func(db *gorm.DB) error {
// 这个方式已经过时了...
return nil
// 创建 DBConfig,为指定类型注册序列化/反序列化逻辑
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Resolver: resolver.FullSaveResolver{
Resolvers: map[reflect.Type]resolver.Resolver{
reflect.TypeOf(net.IP{}): &IPResolver{}, // 自定义 net.IP 解析器
},
},
})
// 更现代的方式是用 GORM 的 Resolver
type MyType string
// 注册一个自定义数据类型解析器
// 适用于无法给已有类型添加方法的情况
```
> [!info] 注意
> GORM 对全局类型注册的 API 在不同版本间有变化。推荐的实践是给类型加上方法实现 Valuer/Scanner——这样代码内聚性更好,依赖也更清晰。
> [!tip] 何时使用 Resolver?
> - **场景一**:第三方包提供的类型,无法添加方法实现 Valuer/Scanner
> - **场景二**:项目中大量地方用到同一自定义类型,避免每个文件重复实现接口
> - **首选方案**:仍然是直接给类型实现 `driver.Valuer` + `sql.Scanner`——代码内聚性更好,IDE 也能做类型检查
## AutoMigrate 时的自定义类型
@@ -193,12 +192,12 @@ type MyType string
```mermaid
flowchart TD
A[字段类型 T] --> B{T 实现<br/>GORMDataType?}
B -->|是| C["使用返回值<br/>作为列类型"]
B -->|否| D{"T 是已知内置类型?"}
D -->|是| E["使用默认映射"]
D -->|否| F["尝试 driver.Valuer<br/>推断类型"]
F --> G["使用 driver.Value<br/>的反射结果"]
A["字段类型 T"] --> B{"是否实现 GORMDataType?"}
B -- "是" --> C["使用返回值作为列类型"]
B -- "否" --> D{"T 是已知内置类型?"}
D -- "是" --> E["使用默认映射"]
D -- "否" --> F["尝试从 driver.Valuer 推断"]
F --> G["根据 driver.Value 反射确定"]
style A fill:#4FC08D,color:#fff
style C fill:#3B82F6,color:#fff