Golang 连接 PostgreSQL 数据库并读取数据详解

晚来风
晚来风
发布时间:2026-10-15 | 2人浏览过
原创

在 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 数据库编程的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表