Go中的微服务:访问PostgreSQL

363 阅读3分钟

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代码是类型安全的,并尽可能使用具体类型。

它的工作方式是。

  1. 编写SQL语句时明确指出要使用的字段和表。
  2. SQL语句包括注释,以表明指令sqlc 理解。
  3. sqlc 执行,以SQL文件作为输入(通过 )。go:generate
  4. 生成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

自动生成的代码不仅能正确地传入参数,还能根据需要扫描结果。

总结

squirrelsqlc 都是互补的软件包,目的是在访问数据库时改善我们的工作流程,它们肯定有不同的目标,但最终都允许我们在与PostgreSQL交互时减少所需的手动模板,在需要更困难的查询时给予我们一些灵活性。

接下来是最后一篇文章,我们将把这一切放在一起,我将与你分享我在与PostgreSQL交互时喜欢使用的软件包,更重要的是我为什么最终使用它们。