在 Go 中直接从文件或字符串执行 SQL 脚本

Dac*_*d3r 5 postgresql go

在我的应用程序的安装脚本中,我正在检查数据库是否包含任何表。如果数据库为空,我想运行 DML 和 DDL SQL 脚本。

它从一个单独的 .sql 文件中读取 SQL 并不重要,所以现在我只是将它直接放入两个字符串 - 一个用于 DDL,一个用于 DML - 并将它们连接起来。

我现在的问题是,当我尝试运行脚本以使用 .Exec(sqlStr) 生成表并将数据插入其中时,我现在收到此错误:

"pq: cannot insert multiple commands into a prepared statement"
Run Code Online (Sandbox Code Playgroud)

我当然可以做一个解决方法。就像是:

sqlStr := sqlDML + sqlDDL
sqlStmtSlice := strings.Split(sqlStr, ";")
for i:= 0; i < len(sqlStmtSlice) i++ {
    // Exec() each individual statement!
}
Run Code Online (Sandbox Code Playgroud)

但是,我不确定我是否喜欢这种方法。当然必须有更好的方法来从文件加载 SQL 脚本并执行整个批处理,对吗?你知道吗?

附言。我正在使用 Go 的 PostgreSQL 驱动程序,但我认为这没有任何区别。

编辑

由于当时似乎没有更好的解决方案来完成这项工作,因此我对上面的伪代码做了一些改进,经过测试,似乎工作得很好:

tx, err := db.Begin()

sqlStr := fmt.Sprintf(sqlDML + sqlDDL)
sqlStmtSlice := strings.Split(sqlStr, ";\r")

if err != nil {
    return err
}

defer func() {
    _ = tx.Rollback()
}()

for _, q := range sqlStmtSlice {
    _, err := tx.Exec(q)

    if err != nil {
        return err
    }
}

err = tx.Commit()
Run Code Online (Sandbox Code Playgroud)

Elw*_*nar 6

据我所知,如果不允许多个语句查询,则没有真正更好的方法。它与您使用的驱动程序无关,因为这是一个database/sql包限制。争论它是否是一个好的设计是另一个问题(我相信已经有很多了)。

在替代方案方面,您可能可以使用 SQL 架构迁移工具或从它们中获得灵感。一般约定是使用语义上惰性的标记,例如评论,并围绕这些进行拆分。

golang中的例子,你可以看到:

  • goose:功能齐全,可以用 Go 编写迁移
  • 漫步者:轻量级,仅 SQL

免责声明:我是rambler的开发者。也就是说,您绝对应该看看goose,这真的很酷。