Golang 从入门到放弃 -0x0F

database/sql 入门:连接数据库、CRUD、事务,以及连接池的基本认知。

前面我们已经能写出最基本的 HTTP 服务了。接下来这个坑几乎谁都绕不过去:数据库。理论上你也可以把数据都放内存里,然后重启一次喜提失忆,但那样很快就会把自己送走。

先认识 database/sql

Go 标准库里和数据库打交道,核心入口通常是 database/sql。它更像一层通用规范,真正连 MySQL、PostgreSQL,还得配合对应驱动。

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

那个下划线导入看着有点怪,但很常见。它表示“我不用直接调用这个包里的东西,但我要它的初始化副作用”。驱动注册基本就靠这个。

连接数据库

dsn := "user:password@tcp(127.0.0.1:3306)/demo?charset=utf8mb4&parseTime=True&loc=Local"
db, err := sql.Open("mysql", dsn)
if err != nil {
    return err
}
defer db.Close()

if err := db.Ping(); err != nil {
    return err
}

这里有个很容易忽略的小点:sql.Open 不一定会立刻真去连库,它更多是在准备一个连接池对象。所以更稳妥的习惯是后面补一发 Ping()

查一条数据

type User struct {
    ID   int
    Name string
    Age  int
}

var user User
row := db.QueryRow("SELECT id, name, age FROM users WHERE id = ?", 1)
err := row.Scan(&user.ID, &user.Name, &user.Age)
if err != nil {
    return err
}

Scan 的时候别忘了传地址,不然数据往哪儿写都成问题。

查多条数据

rows, err := db.Query("SELECT id, name, age FROM users")
if err != nil {
    return err
}
defer rows.Close()

users := make([]User, 0)
for rows.Next() {
    var user User
    if err := rows.Scan(&user.ID, &user.Name, &user.Age); err != nil {
        return err
    }
    users = append(users, user)
}

if err := rows.Err(); err != nil {
    return err
}

这里最后那句 rows.Err() 不要省。很多人遍历完就直接走人,结果把中途出错的信息漏掉了。

写数据

增删改大多走 Exec

result, err := db.Exec(
    "INSERT INTO users(name, age) VALUES(?, ?)",
    "Raymond",
    18,
)
if err != nil {
    return err
}

id, _ := result.LastInsertId()
fmt.Println("new id:", id)

更新、删除也差不多,主要看返回的 RowsAffected()

事务别只会听过

只要你的业务里有“这几步要么一起成功,要么一起失败”,事务就该出场了。

tx, err := db.Begin()
if err != nil {
    return err
}

defer tx.Rollback()

if _, err := tx.Exec("UPDATE users SET age = age + 1 WHERE id = ?", 1); err != nil {
    return err
}

if _, err := tx.Exec("UPDATE users SET age = age - 1 WHERE id = ?", 2); err != nil {
    return err
}

if err := tx.Commit(); err != nil {
    return err
}

这里的套路建议你养成肌肉记忆:先 Begin,马上 defer Rollback(),全部成功后再 Commit()。这样就算中途 return 了,也不至于留下半截事务在那儿发呆。

连接池也要有点概念

db 不是一个单连接,它背后其实是连接池。默认值有时候不一定合适,服务一上量就可能出现各种奇奇怪怪的问题。

db.SetMaxOpenConns(20)
db.SetMaxIdleConns(10)
db.SetConnMaxLifetime(time.Hour)

这些参数没有什么一刀切神仙值,核心还是看你的数据库配置、业务并发和部署环境。但至少你要知道它们存在,不要把数据库性能问题全怪给“Go不行”。

小结

这一章你先把这些能力点拿住:

  • sql.Open 是入口,Ping 用来确认真的能连上。
  • QueryRow 查一条,Query 查多条,Exec 做增删改。
  • 事务是业务一致性的底线,不是装饰品。
  • db 背后是连接池,参数别完全没概念。

下一章我们说测试。写代码全靠信仰也不是不行,但一般坚持不了太久。

Read more

Harness Engineering:从驾驭模型到构建 AI 工厂

Harness Engineering:从驾驭模型到构建 AI 工厂

2026 年,AI 编程工具的竞争焦点发生了根本性转变:决定 AI 助手好不好用的,不再是模型本身,而是包裹在模型外面的那层"Harness"。同一个模型,在不同的 Harness 下,性能差距可以达到 78% vs 42%。 这篇文章将带你深入了解 Harness Engineering——这个正在重新定义 AI 工程实践的新兴领域。 一、什么是 Harness Engineering? Harness 的字面意思是"马具/缰绳"——用来驾驭一匹强壮但不受控的马。在 AI 语境下,Harness 就是 LLM 之外的一切:工具定义、记忆系统、权限模型、反馈循环、文档规范、多

By Fuyu Jia

Claude Code CLI + Ralph:让 AI 自动完成大型编程任务的终极方案

TL;DR 当你的编程任务大到一个 AI 对话窗口装不下时,Ralph 会帮你把任务拆成小块,让 Claude Code CLI 一个接一个地自动完成——每轮都用全新的上下文窗口,不会越写越糊涂。 一、什么是 Ralph? Ralph 是一个开源项目(GitHub 16k+ Stars),基于 Geoffrey Huntley 提出的 "Ralph Pattern" 构建。它的核心理念很简单: 不要让 AI 在一个漫长的会话里做完所有事情,而是把大任务拆成小故事,每个故事用一个全新的 AI 实例来完成。 这解决了 AI 编程中最常见的痛点——上下文窗口耗尽。当对话越来越长,AI 的输出质量会明显下降。Ralph 通过「每轮一个新实例」的方式,

By Fuyu Jia