一、问题引入?
笔者在学习一个项目时,有一个登录需求,在登录时需要判断用户是否存在,特引入了Find方法做查询,然后根据返回值做判断,没想到因为Find的特性,导致判断存在问题,不管用户名是否存在,都会返回一个user实例,导致登录逻辑出错
二、分析
1、初始代码如下:
//判断用户名是否存在
func (dao *UserDao) ExistOrNotByUserName(userName string) (user *model.User, exist bool, err error) {err = dao.DB.Model(&model.User{}).Where("user_name=?", userName).Find(&user).Errorif user == nil || err == gorm.ErrRecordNotFound { //判断逻辑,问题所在点return nil, true, err}return user, false, nil
}//登录判断
func (service *UserService) Login(ctx context.Context) serializer.Response {var user *model.Usercode := e.SuccessuserDao := dao.NewUserDao(ctx)user, exist, err := userDao.ExistOrNotByUserName(service.UserName)fmt.Println("user:", user, ":exist", exist, ":err:", err)if exist || err != nil {code = e.ErrorExistUserNotFoundreturn serializer.Response{Status: code,Msg: e.GetMsg(code),Data: "用户不存在,请先注册",}}
在上述代码中,ExistOrNotByUserName 方法的判断条件中有user == nil 这个选项,正是因为这样,导致不管我输入的用户名是什么,都会进入if语句为true的条件下,使得并没有得到我想要的效果。
2、原因分析
后来经过调试,发现经过Find函数查询后,返回的user是有值的
当用户名不存在时,
Find
操作会返回一个空的user
对象而不是nil
。这是因为gorm
库在查询数据库时,即使没有找到匹配的记录,也不会返回nil
,而是返回一个实例化的对象。这是因为
gorm
库的默认行为,尤其是当使用Find
函数时。当gorm
执行查询但没有找到记录时,它会返回一个实例化的对象,并将该对象的主键字段设为零值。model.User
结构体中,主键字段是ID
。
3、解决方法
(1)还是使用Find函数,但是增加判断条件
// ExistOrNotByUserName 根据UserName判断是否存在该名字
func (dao *UserDao) ExistOrNotByUserName(userName string) (user *model.User, exist bool, err error) {err = dao.DB.Model(&model.User{}).Where("user_name=?", userName).Find(&user).Errorif err == gorm.ErrRecordNotFound || (user != nil && user.ID == 0) {return nil, false, err //用户不存在} else if err != nil {return nil, true, err //查询时出现错误}return user, false, nil //用户存在
}func (service *UserService) Login(ctx context.Context) serializer.Response {var user *model.Usercode := e.SuccessuserDao := dao.NewUserDao(ctx)user, exist, err := userDao.ExistOrNotByUserName(service.UserName)fmt.Println("user:", user, ":exist", exist, ":err:", err)if user == nil || err != nil {code = e.ErrorExistUserNotFoundreturn serializer.Response{Status: code,Msg: e.GetMsg(code),Data: "用户不存在,请先注册",}}
(2)使用First函数
func (dao *UserDao) UserExists(userName string) (bool, error) {var user model.Usererr := dao.DB.Where("user_name=?", userName).First(&user).Errorif err == gorm.ErrRecordNotFound {return false, nil // 用户不存在} else if err != nil {return false, err // 查询时出现错误}return true, nil // 用户存在
}