一、定义表模型时区问题

1.1 time.Time 与int64

一般情况下,我们在定义表模型的时候,会使用time.Time,但是会根据当前时间存储。返回给前端的时候做时区转换会比较复杂,所以一般用int64:

// User 直接对应数据库中的表
// 有些人叫做entity,有些人叫做model
type User struct {
    Id int64 `gorm:"primaryKey,autoIncrement"`
    // 全部用户唯一
    Email    string `gorm:"unique"`
    Password string

    // 创建时间,毫秒数,使用int64解决时区问题
    Ctime int64
    // 更新时间
    Utime int64
}

1.2 优势

在定义数据库表模型时,选择使用 int64 类型来表示时间戳有一些考虑和优势,尤其是在处理时区问题时。以下是一些优势和考虑因素:

  1. 时区一致性: 使用 int64 表示时间戳可以避免在前端和后端之间进行时区转换的复杂性。int64 类型的时间戳是相对于某个固定的基准时间(通常是UNIX纪元)的毫秒数,不涉及时区信息。这样,你就可以更轻松地在前端和后端之间传递和处理时间信息,而不必担心时区转换引起的问题。
  2. 序列化和传输: 使用 int64 类型的时间戳可以更方便地在网络上传输和序列化,因为它是一个数字。对于前后端通信而言,时间戳是一种常见的时间表示方式。
  3. 易于处理: 在一些情况下,直接使用 int64 类型的时间戳可能更容易处理。例如,你可以轻松进行比较、排序和其他与时间相关的计算,而不涉及时区信息。这在某些业务场景下可能是一种简化处理的方式。
  4. 避免时区混淆: 时区问题可能引起一系列复杂的 bug,而使用 int64 类型可以避免这些问题,只有返回给用户的时候才需要处理时区问题,数据库存储永远是UTC不会出错。并且前端可以直接使用这个时间戳做转换。

二、unique唯一索引字段数据冲突问题

举个例子,当两个用户同时访问,注册同一个邮箱,当线程1插入会成功,线程2插入不会成功,并且会返回系统错误,这会对用户造成很不好的影响。

所以一般使用唯一索引冲突错误码1062来判断。

// ErrUserDuplicateEmail 表示用户邮箱重复的错误
var ErrUserDuplicateEmail = errors.New("邮箱冲突")

// Insert 将用户数据插入数据库
func (dao *UserDAO) Insert(ctx context.Context, u User) error {
    // 存储当前时间的毫秒数
    now := time.Now().UnixNano()
    u.Ctime = now
    u.Utime = now

    // 使用Gorm的Create方法将用户数据插入数据库
    err := dao.db.WithContext(ctx).Create(&u).Error

    // 类型断言,判断是否是MySQL的唯一冲突错误
    if mysqlErr, ok := err.(*mysql.MySQLError); ok {
        const uniqueConflictsErrNo uint16 = 1062
        // MySQL错误码1062表示唯一冲突
        if mysqlErr.Number == uniqueConflictsErrNo {
            // 返回自定义的唯一冲突错误
            return ErrUserDuplicateEmail
        }
    }

    // 返回其他数据库操作可能出现的错误
    return err
}

贾维斯Echo
4 声望4 粉丝