You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Gorm映射原生查询结果到DTO时的查询执行异常问题

问题排查:Gorm原生查询无法执行

定义的Gorm模型

type User struct {
    gorm.Model
    Username string
    Password string
}

type Assistant struct {
    gorm.Model
    UserID        int
    User          User
    InstitutionID int
}

type Professor struct {
    gorm.Model
    UserID        int
    User          User
    InstitutionID int
}

两种原生查询实现

第一种实现

var users *[]model.User
db.Raw("SELECT u.id, u.username "+
    "FROM users u "+
    "LEFT JOIN assistants ass ON ass.user_id = u.id "+
    "LEFT JOIN professors prof ON prof.user_id = u.id "+
    "WHERE (u.username = @username1 AND ass.institution_id = @ins1)"+
    "      or                                           "+
    "      (u.username = @username2 AND prof.institution_id = @ins2)",
    map[string]interface{}{"username1": dto.Username, "ins1": dto.InstitutionID, "username2": dto.Username, "ins2": dto.InstitutionID},
).Find(&users)

第二种实现

var users *[]model.User
db.Raw("SELECT u.id, u.username "+
        "FROM users u "+
        "LEFT JOIN assistants ass ON ass.user_id = u.id "+
        "LEFT JOIN professors prof ON prof.user_id = u.id "+
        "WHERE ( u.username = ? AND ass.institution_id = ? )"+
        "      or                                           "+
        "      (u.username = ? AND prof.institution_id = ?) RETURNING id, username", dto.Username, dto.InstitutionID, dto.Username, dto.InstitutionID).Scan(&users)

控制台错误日志

goroutine 20 [running]:
        C:/Program Files/Go/src/net/http/server.go:2122 +0x2f
github.com/gorilla/mux.(*Router).ServeHTTP(0xc000000480, {0xf09690, 0xc0001501c0}, 0xc000212000)
        C:/Users/Miljan.Puletic/go/pkg/mod/github.com/gorilla/mux@v1.8.0/mux.go:210 +0x1cf
        C:/Program Files/Go/src/net/http/server.go:2122 +0x2f
github.com/gorilla/mux.(*Router).ServeHTTP(0xc000000480, {0xf09690, 0xc0001501c0}, 0xc000212000)
        C:/Users/User/go/pkg/mod/github.com/gorilla/mux@v1.8.0/mux.go:210 +0x1cf
net/http.serverHandler.ServeHTTP({0xf08698?}, {0xf09690, 0xc0001501c0}, 0xc000212000)
        C:/Program Files/Go/src/net/http/server.go:2936 +0x316
net/http.(*conn).serve(0xc000408ab0, {0xf09bf8, 0xc000422030})
        C:/Program Files/Go/src/net/http/server.go:1995 +0x612
created by net/http.(*Server).Serve
        C:/Program Files/Go/src/net/http/server.go:3089 +0x5ed

排查修复要点

1. MySQL不支持RETURNING子句

第二个查询中添加的RETURNING id, username是PostgreSQL专属语法,MySQL无此特性,这是查询失败的直接原因,删除该子句即可。

2. 切片变量声明错误

代码中var users *[]model.User声明的是指针切片,Gorm的Scan/Find方法需要接收值切片的指针,正确声明应为var users []model.User,然后传递&users给方法。未初始化的指针切片会引发空指针panic,对应日志中的goroutine报错。

3. 命名参数格式错误

第一种实现中使用@username1格式的命名参数,Gorm对MySQL的命名参数支持是:前缀(如:username1)而非@,改用该格式或直接使用?占位符即可正常绑定参数。

4. 查询逻辑优化(可选)

原查询用LEFT JOIN可能返回重复数据,改用EXISTS子查询可提升性能并避免重复结果,优化后的SQL如下:

SELECT u.id, u.username 
FROM users u 
WHERE (u.username = ? AND EXISTS (SELECT 1 FROM assistants ass WHERE ass.user_id = u.id AND ass.institution_id = ?))
OR (u.username = ? AND EXISTS (SELECT 1 FROM professors prof WHERE prof.user_id = u.id AND prof.institution_id = ?))

修复后的代码示例

var users []model.User
err := db.Raw(`
    SELECT u.id, u.username 
    FROM users u 
    WHERE (u.username = ? AND EXISTS (SELECT 1 FROM assistants ass WHERE ass.user_id = u.id AND ass.institution_id = ?))
    OR (u.username = ? AND EXISTS (SELECT 1 FROM professors prof WHERE prof.user_id = u.id AND prof.institution_id = ?))
`, dto.Username, dto.InstitutionID, dto.Username, dto.InstitutionID).Scan(&users).Error

if err != nil {
    log.Printf("查询用户失败: %v", err)
    // 此处添加HTTP错误处理逻辑
    return
}

额外调试建议

开启Gorm详细日志,可查看实际执行的SQL语句和错误详情,初始化DB时配置:

db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
    Logger: logger.Default.LogMode(logger.Info),
})

内容的提问来源于stack exchange,提问作者Wrapper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 14:27:15