如何验证数据库字段的唯一性?环境:Gin+GORM+[go-playground/validator]

我用这个框架 Gin+GORM+[go-playground/validator v10] 目前遇到了一些问题, 我设置了gorm设置数据库用户表中的username字段unique唯一。 设想是当用户注册的时候,输入已存在的用户名username会提示已经注册了!

请问我应该如何实现唯一性的判断呢?我在User结构体上设置了tag,validate:”unique=users”。 但是validator好像不能这么用。

type User struct {
    gorm.Model
    Username string `gorm:"unique;notnull" validate:"unique=users"`
    Password string `gorm:"notnull"`
    PasswordConfirmation string `gorm:"-" json:"password_confirmation" binding:"required" validate:"required,eqfield=Password"`
}
讨论数量: 5

最好是通用性设计,我希望比如打tag这样,要不然以后好几个字段都是unique不至于一个一个手写。

4年前 评论
DukeAnn

那是交互的设计,用户指针离开输出窗,就查库去了。

4年前 评论

你这种需求需要写一个接口查询是否名称已经存在。 validate 这个是提交表单的时候做数据验证的,没法做到用户输入完就验证。如果你想如何做表单数据验证,可以看下我的这项目https://github.com/snowlyg/IrisAdminApi 。框架虽然是 iris ,但是数据库用的是 gorm ,数据验证处理是通用的。

4年前 评论

通过自定义验证方法可实现,我是用database/sql实现的,下面说说我的思路。

一,validator自定义函数中定义一个结构体用来保存查询结果

/xxxx/自定义验证器/Unique.go

type dataStruct struct {
    DataCount int //这个结构体用来保存查询到的记录条数
}

在自定义验证器中

func Unique(fl validator.FieldLevel) bool {
    var data dataStruct  //用于接收结构体
    sqlStr := fmt.Sprintf("SELECT COUNT(*) AS `DataCount` FROM `%s` WHERE `%s`=?",fl.Param(), fl.FieldName()[:strings.Index(fl.FieldName(),"|")]) 
        /*
            这里构建了一个sql查询语句,必须在这里先构建一次,?号只能用于参数,字段和表名无法使用
            其中fl.Param()是获取表名,也就是unique=users里的users
           fl.FieldName()[:strings.Index(fl.FieldName(),"|")]这里请无视,因为我自己构建了返回格式,如果没有自定义过就直接用fl.FieldName()返回字段名字就行了,例如你的Username(记得小写和去除结构体,总之自己拼对要验证的字段名就行了)
        */

        // database/sql的单行查询,把sql查询到的数字扫描到公共结构体内
    err := app.DB.QueryRow(sqlStr,fl.Field().String()).Scan(&data.DataCount)

    if err != nil{
        panic("出错了!无视这里,扫描失败的情况下触发")
    }
    if data.DataCount > 0 {
               // 如果记录总数大于0 说明存在记录,直接返回false即可
        return false
    }
        // 没触发false就说明没有重复记录,返回true
    return true
}

使用参考:

type UserClientApp struct {
    UserName string `label:"用户名" form:"username" json:"username" binding:"required,min=5,max=10,unique=users"`
    Password string `label:"密码" form:"password" json:"password" binding:"required,min=8,max=16"`
    Email string `label:"邮箱" form:"email" json:"email" binding:"required,email,unique=users"`
}

缺点很明显:

1.必须是一个字段一个字段的进行查询,如果唯一的太多太影响性能。

2.因为无法获取结构体的名字,除非设定一个标准弄一行空验证存储结构体名字且结构体名和表名对应(太麻烦),在使用中必须使用unique=【表名】的方法来设定验证

至于如何注册自定义验证器,自定义验证器的中文等等,请百度。内容太多太散懒得整理了,以上代码无法直接拷贝使用,是从我的试验性代码里拷贝出来的。

3年前 评论

上周也遇到了这个问题

  1. 这个字段唯一值校验,应该指定表和字段,  不能仅仅指定表(默认主键), unique=users email 这种配置是否更好
  2. 考虑到更新的存在,有没有存在回写被误校验的可能
3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!