Go中的微服务。访问PostgreSQL(第3部分)--语句生成器和代码生成器
Feb 23, 2021
下面的例子使用一个结构如下的数据库表。
-- db/migrations/20210126023417_create_names_table.up.sql
CREATE TABLE names (
nconst varchar(255),
primary_name varchar(255),
birth_year varchar(4),
death_year varchar(4) DEFAULT '',
primary_professions varchar[],
known_for_titles varchar[]
);
使用语句生成器和代码生成器
上两篇文章涵盖了与PostgreSQL数据库交互的相反方式,要么所有的调用都是手动编写的,要么都是通过某种机制自动生成的,这篇文章将把这两种想法结合起来,用两种不同的方法来处理动态构建的和静态构建的SQL语句。
涉及的两个包是。
Masterminds/squirrel
Masterminds/squirrel是一个允许你使用流畅的API生成SQL语句的包,它也支持使用这些构建的语句直接进行数据库调用。
squirrel 不是针对PostgreSQL的,理论上它应该与任何支持标准SQL的数据库引擎一起工作,为了使用它,我们必须把我们的查询分成几个部分,这意味着我们不需要手动编写要执行的字面SQL语句,而是利用包中定义的类型,比如说。
// postgresql_squirrel.go
var res Name
query := sq.
Select("nconst", "primary_name", "birth_year", "death_year").
From("names").
Where("nconst = ?", nconst).
PlaceholderFormat(sq.Dollar).
RunWith(p.db)
if err := query.
ScanContext(context.Background(), &res.NConst, &res.Name, &res.BirthYear, &res.DeathYear); err != nil {
return Name{}, err
}
return res, nil
有一点需要立即指出的是,虽然创建SQL语句比以前更方便了,但我们仍然需要为每个返回的字段明确调用Scan() ,这与使用database/sql 。
squirrel 在建立动态语句时,这个包真的很有用,例如,考虑到我们要建立的语句取决于某些条件,而这些条件会影响我们要与哪些列或表进行交互。
这就是这个包的用处,因为我们可以使用squirrel ,正确地生成一个带有我们需要的适当占位符的语句,而不是手工构建一个字符串。它为我们节省了一些时间,并使代码更容易理解。
kyleconroy/sqlc
kyleconroy/sqlc是SQL编译器,它从字面的SQL语句中生成类型安全的代码,它支持PostgreSQL和MySQL。
sqlc 的杀手锏是,因为它使用了PostgreSQL引擎,所以可以检测到我们查询中的SQL错误,比如语法错误或丢失字段;不仅如此,生成的Go代码是类型安全的,并尽可能使用具体类型。
它的工作方式是。
- 编写SQL语句时明确指出要使用的字段和表。
- SQL语句包括注释,以表明指令
sqlc理解。 sqlc执行,以SQL文件作为输入(通过 )。go:generate- 生成Go类型。
之后,我们可以轻松地与数据库进行交互,例如。
// postgresql_sqlc.go
row, err := New(p.db).SelectName(context.Background(), sql.NullString{String: nconst})
if err != nil {
return Name{}, err
}
return Name{
NConst: row.Nconst.String,
Name: row.PrimaryName.String,
BirthYear: row.BirthYear.String,
DeathYear: row.DeathYear.String,
}, nil
自动生成的代码不仅能正确地传入参数,还能根据需要扫描结果。
总结
squirrel 和sqlc 都是互补的软件包,目的是在访问数据库时改善我们的工作流程,它们肯定有不同的目标,但最终都允许我们在与PostgreSQL交互时减少所需的手动模板,在需要更困难的查询时给予我们一些灵活性。
接下来是最后一篇文章,我们将把这一切放在一起,我将与你分享我在与PostgreSQL交互时喜欢使用的软件包,更重要的是我为什么最终使用它们。