在这里插入图片描述

起因

这是昨天中午楼下吃饭偶然吃到的瓜。
我与另一个同事在一桌用餐,隔壁桌新来了一个人(后续称为瓜),看着也不大,28左右。刚点完餐电话就来了。
由于当时吃饭人也多,就只能听清他的声音。
电话那头:“。。。。。。”
瓜:“没有啊,我这边今天什么也没动”
电话那头:“。。。。。。”
瓜:“我昨天发的0.1.3版本,今天没有动”
瓜:“今天他们发的1.2分支,跟我这个没关系啊”
电话那头:“.。。。。。。”
瓜:“我这边也没有动数据库”
电话那头:“。。。。。。”
瓜:“我就直接select * 然后查出来了”
瓜:“我今天也没有动数据库”
电话那头:“。。。。。。”
瓜:“那这个没有办法啊,可能他们改数据库影响到了”
后续还扯了几句,看瓜的状态双方应该都比较激动,后来他匆匆吃了几口就跑了。

分析

其实当瓜说到“select *”的时候我就大概猜到什么问题了。
因为我给公司制定的开发规范中的一条就是“代码中禁止使用select * ”
原因有二

  • select * 意味着该SQL大概率是要回表的,但是很多场景下,业务只需要部分字段,完全可以使用select column覆盖索引的方式避免回表,从而提升性能。
  • 假设A表涉及多个业务,代码中使用结构体接收select 的所有字段,另一个人需要对A表进行增减字段,这时使用select 的代码就会异常。

我猜测该瓜也是遇到了第二种情况,自己用了select ,但是别的业务也会用该表,别人根据需要对表字段进行了增减,他的select 直接爆炸。

附上伪代码

package main

import (
    "database/sql"
    "fmt"

    _ "github.com/go-sql-driver/mysql"
)

type Person struct {
    ID   int
    Name string
    Age  int
}

func main() {
    // 设置 MySQL 连接信息
    dsn := "xxx:xxx@tcp(xxx.xxx.xxx.xxx:3306)/test_2"

    // 连接数据库
    db, err := sql.Open("mysql", dsn)
    if err != nil {
        fmt.Println("Failed to connect to database:", err)
        return
    }
    defer db.Close()

    // 使用select * 查询 t2的表数据
    rows, err := db.Query("SELECT * FROM t2")
    if err != nil {
        fmt.Println("Failed to query database:", err)
        return
    }
    defer rows.Close()

    // 遍历查询结果并映射到结构体
    var people []Person
    for rows.Next() {
        var p Person
        if err := rows.Scan(&p.ID, &p.Name, &p.Age); err != nil {
            fmt.Println("Error scanning row:", err)
            return
        }
        people = append(people, p)
    }

    // 打印查询结果
    for _, p := range people {
        fmt.Printf("ID: %d, Name: %s, Age: %d\n", p.ID, p.Name, p.Age)
    }

    if err := rows.Err(); err != nil {
        fmt.Println("Error in rows:", err)
        return
    }
}

2024-06-05T05:45:36.png

数据库表新增字段后

2024-06-05T05:45:51.png

彩蛋

如果没有数据库相关的开发规范,像这种坑被踩烂了都会有人继续踩。