Golang 连接 PostgreSQL 数据库并读取数据详解
在 Go 开发中,将数据库配置外部化是提升项目灵活性的关键步骤。本文将演示如何结合 encoding/json 与 database/sql,实现从 JSON 配置文件读取 PostgreSQL 参数,并通过 lib/pq 驱动完成连接与数据查询。
准备环境与依赖
要实现 Golang 与 PostgreSQL (Pgsql) 的交互,需确保本地已安装 Go 环境及 PostgreSQL 服务。在代码架构中,我们通常采用分层设计以解耦配置读取与数据库操作:
config/config.go:负责解析配置文件,将 JSON 数据映射为结构体对象。config/config.json:存放数据库连接所需的账号、密码、地址及表名等参数。handle/handle.go:核心逻辑层,处理数据库连接创建、SQL 执行及结果扫描。main.go:入口文件,调度各模块执行。
第一步:定义数据结构并加载配置
首先,定义一个结构体来映射 JSON 中的字段。Go 的结构体标签(json tag)决定了序列化时的键名。随后通过 os.Open 读取文件并利用 json.Unmarshal 将内容注入到全局变量或配置结构中。
package config
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
)
type Pgsql struct {
Username string `json:"username"`
Password string `json:"password"`
Address string `json:"address"`
Port int `json:"port"`
Database string `json:"database"`
Table string `json:"table"`
AccountField string `json:"accountField"`
PwdField string `json:"pwdField"`
}
// 配置文件路径常量
var ConfigPath string = "config/config.json"
// 全局配置对象缓存
var PgsqlData *Pgsql
func Init() {
// 初始化指针
PgsqlData = new(Pgsql)
// 打开配置文件
file, err := os.Open(ConfigPath)
if err != nil {
fmt.Println("Failed to open config path:", err)
os.Exit(1)
}
defer file.Close()
// 读取所有字节
bytes, err := ioutil.ReadAll(file)
if err != nil {
fmt.Println("Failed to read config file:", err)
os.Exit(1)
}
// 解析 JSON 到结构体
err = json.Unmarshal(bytes, PgsqlData)
if err != nil {
fmt.Println("JSON unmarshal error:", err)
os.Exit(1)
}
}
对应的配置文件 config.json 示例如下:
{
"username": "your_db_user",
"password": "your_db_password",
"address": "localhost",
"port": 5432,
"database": "testdb",
"table": "users",
"accountField": "username_col",
"pwdField": "password_col"
}
第二步:建立数据库连接
在 handle 包中,我们需要引入第三方驱动 github.com/lib/pq(注意:使用时需在 import 中添加下划线 _ 以触发驱动注册),以及标准库 database/sql。
使用 sql.Open 时,第一个参数指定驱动名称为 "postgres",第二个参数为 DSN (Data Source Name) 字符串。建议拼接时使用 fmt.Sprintf,并确保包含 sslmode=disable(本地开发常见配置)。
package handle
import (
"database/sql"
"errors"
"fmt"
"pgsql/config"
// 导入 pq 驱动以注册驱动名称
_ "github.com/lib/pq"
)
func Execute() error {
// 1. 确保配置已加载
config.Init()
if config.PgsqlData == nil {
return errors.New("configuration not loaded")
}
// 2. 构建连接字符串 (DSN)
dsn := fmt.Sprintf(
"host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
config.PgsqlData.Address,
config.PgsqlData.Port,
config.PgsqlData.Username,
config.PgsqlData.Password,
config.PgsqlData.Database,
)
// 3. 打开数据库连接
db, err := sql.Open("postgres", dsn)
if err != nil {
return fmt.Errorf("failed to connect: %w", err)
}
// 务必使用 defer 确保连接在服务结束或函数退出时关闭
defer db.Close()
// 可选:检查连接是否有效
if err := db.Ping(); err != nil {
return fmt.Errorf("ping failed: %w", err)
}
// ... 后续查询逻辑
return nil
}
第三步:执行查询与结果处理
连接成功后,根据配置中的字段名构建 SELECT 语句。为了安全起见,实际生产环境中建议使用参数化查询(Prepared Statement)以防止 SQL 注入,但在本示例中,我们按照配置动态提取列名进行演示。
func executeQuery(db *sql.DB) (*string, *string, error) {
// 构建查询语句,这里动态引用了配置中的表和字段名
query := fmt.Sprintf(
"SELECT %s, %s FROM %s WHERE name = $1",
config.PgsqlData.AccountField,
config.PgsqlData.PwdField,
config.PgsqlData.Table,
)
// 使用 QueryRow 获取单行结果,$1 占位符传入搜索条件
row := db.QueryRow(query, config.PgsqlData.Username)
var name, pwd sql.NullString
// 扫描结果
err := row.Scan(&name, &pwd)
if err != nil {
return nil, nil, err
}
// 验证数据是否为空
if !name.Valid || !pwd.Valid {
return nil, nil, errors.New("record data is null or invalid")
}
return &name.String, &pwd.String, nil
}
第四步:主函数调用与错误处理
最后,在 main.go 中串联上述步骤。如果任何环节出现错误,程序应记录日志并安全退出。
package main
import (
"fmt"
"os"
"pgsql/handle"
)
func main() {
// 执行数据库操作
err := handle.Execute()
if err != nil {
fmt.Printf("Execution failed: %v\n", err)
os.Exit(1)
}
fmt.Println("Operation completed successfully.")
}
排错与注意事项
- 驱动未注册:如果在
sql.Open时返回未知驱动错误,请确认已正确导入_ "github.com/lib/pq"。 - 权限问题:若连接被拒绝,请检查 PostgreSQL 的
pg_hba.conf配置,确保允许来自该 IP 的用户名/密码认证。 - 资源泄露:务必使用
defer db.Close(),否则数据库连接句柄可能耗尽。 - SQL 注入风险:示例中使用了动态拼接表名和列名,这在特定业务场景下可接受,但若用户输入参与条件值,必须使用
$1,$2等占位符绑定参数。
总结
通过上述步骤,我们实现了 Golang 与 PostgreSQL 的动态配置连接。这种方式不仅提高了代码的可移植性,也便于在不同环境下快速切换数据库源。以上就是 Golang 与 PostgreSQL 交互实现的详细内容,更多关于 Golang 数据库编程的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









