# 4.2 数据模型的扩充处理

#### 4.2.1 分离字段存储到Redis中

在上一个章节中，我们能够正常的读写数据库，创建一条提示词。但是其中

```go
type Prompts struct {
    ...
    ...
    Body string `json:"Body" form:"Body" gorm:"column:body;comment:;type:text;"`
}
```

这里的Body(提示词正文)部分还是以`TEXT`的方式保存在MySQL的。

如果我们想要将其放在Redis中，那么需要对Model进行一些改造，而且在改造以后要对业务透明。这样我们的业务逻辑不需要去管存储介质和存储路径。

```go
type Prompts struct {
    ...
    ...
    Body string `json:"Body" form:"Body" gorm:"-:all"`
}
```

通过将`gorm:"-:all"`将这个字段从orm的绑定上删除，这样读写的时候gorm不会管这个字段。

然后在模型中补充两个函数:

```go

func (p *Prompts) AfterCreate(tx *gorm.DB) (err error) {
    // 将Redis中存储键交给getRedisKey，而不是每次自己拼凑，防止拼写错误
	redisKey := p.getRedisKey()
	if global.GVA_REDIS == nil {
		return fmt.Errorf("Redis客户端未初始化")
	}
	err = global.GVA_REDIS.Set(context.Background(), redisKey, p.Body, 0).Err()
	return nil
}

// 根据记录的MySQL中的主键值返回Redis中存储的键名
func (p *Prompts) getRedisKey() string {
	return fmt.Sprintf("prompt_body:%d", p.ID)
}
```

我们再执行`CreatePrompts`的时候，就会自动将数据保存到Redis，并且当插入Redis失败的时候，会自动回滚MySQL的插入操作，以保证数据一致性。

#### 4.2.2 读取数据时，自动补全Redis中的字段

```go
func (p *Prompts) AfterFind(tx *gorm.DB) (err error) {
  // 获取Key,详见上一章
  redisKey := p.getRedisKey()

  // 从Redis获取Value
  if global.GVA_REDIS != nil {
    p.Body, _ = global.GVA_REDIS.Get(redisKey).Result()
  }

  return 
}
```

* 对于Service而言，不关心Model写入数据的逻辑细节，只需要获取其所需的数据，并且做完业务加工以后，扔给Model处理就行；
* 同样对于Controller而言，抑不关心Service的实现，只需要做好数据的验证和参数的获取，然后调用不同的Service协作完成任务。

在传统的软件架构中，模型（Model）、服务（Service）和控制器（Controller）各执其职，它们共同工作以实现软件的业务逻辑和数据处理。**那么到底应该谁轻谁重呢？**

**模型（Model）：**

* **应该相对轻**：模型通常是轻量级的，只定义数据结构和数据库层面的操作。它们应包含数据验证和基本的方法来表达它们的直接数据关系，但避免包含业务逻辑。
* **为什么**：使模型保持轻量可以增加代码的可复用性，并避免模型变得过于复杂，这样在业务逻辑变更时，模型层通常无需变动。

**服务（Service）：**

* **应该相对重**：服务层是应用程序的核心，它应包含大部分的业务逻辑。服务层作为模型和控制器之间的桥梁，负责编排模型方法的调用，处理复杂的业务规则，以及确保数据传输对象和领域模型之间的数据映射。
* **为什么**：将业务逻辑放在服务层可以实现逻辑的集中管理，便于测试和维护，并且可以在不同的控制器之间重用服务逻辑。

**控制器（Controller）：**

* **应该相对轻**：控制器负责接收用户请求并将请求传递给 Service 层。还负责将 Service 层的响应返回给用户。
* **为什么**：轻控制器使得代码更易于阅读和维护，因为它们的工作仅仅是请求的入口和出口点。这种分离也使得控制器成为一种轻薄的适配层，容易适应外部接口的变化。

通过这种分层方式，可以增加应用程序的灵活性和可维护性。服务层的“重”使得业务逻辑更集中、更有条理，而模型和控制器的“轻”则使得系统的其他部分更加灵活，易于适应变化。这样的架构也有利于实现关注点分离（Separation of Concerns），每一层只关心其职责范围内的问题，便于团队协作和代码管理。
