Golang连接数据库时报错:无法连接到`host=localhost user=root database=userdb`(意外EOF导致消息接收失败)

Golang连接数据库时报错:无法连接到host=localhost user=root database=userdb(意外EOF导致消息接收失败) main.go

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/jmechavez/PSO-Sarangani/db"
)

type Config struct {
	Port string
}

type Application struct {
	Config Config
}

// global port varialbe for both main and serve
var port = os.Getenv("PORT")

func (app *Application) Serve() error {
	fmt.Println("API listening on port", port)

	srv := &http.Server{
		Addr: fmt.Sprintf(":%s", port),
	}

	return srv.ListenAndServe()
}

db.go


package db

import (
	"database/sql"
	"fmt"
	"time"

	_ "github.com/jackc/pgconn"
	_ "github.com/jackc/pgx/v4"
	_ "github.com/jackc/pgx/v4/stdlib"
	_ "github.com/lib/pq"
)

type DB struct {
	DB *sql.DB
}

var dbConn = &DB{}

const (
	maxOpenDbConn = 10
	maxIdleDbConn = 5
	maxDbLifeTime = 5 * time.Minute
)

func ConnectPostgres(dsn string) (*DB, error) {
	d, err := sql.Open("pgx", dsn)
	if err != nil {
		return nil, err
	}
	d.SetMaxOpenConns(maxOpenDbConn)
	d.SetMaxIdleConns(maxIdleDbConn)
	d.SetConnMaxLifetime(maxDbLifeTime)

	err = testDB(d)
	if err != nil {
		return nil, err
	}
	dbConn.DB = d
	return dbConn, nil
}

func testDB(d *sql.DB) error {
	err := d.Ping()
	if err != nil {
		fmt.Println("Error", err)
		return err
	}
	fmt.Println("*** Pinged database successfully! ***")
	return nil
}

Makefile


DSN="host=localhost port=5432 user=root password=secret dbname=userdb sslmode=disable timezone=UTC connect_timeout=5"
PORT=8080
DB_DOCKER_CONTAINER=psosarangani_db
BINARY_NAME=psosaranganiapi

# ! creating the container with postgres software
postgres:
	docker run --name ${DB_DOCKER_CONTAINER} -p 5432:5432 -e POSTGRES_USER=root -e POSTGRES_PASSWORD=secret -d postgres:12-alpine


# ! creating the coffee db inside the postgres container
createdb:
	docker exec -it ${DB_DOCKER_CONTAINER} createdb --username=root --owner=root userdb 

#	docker exec -it $(DB_DOCKER_CONTAINER) psql --username=root --command "CREATE DATABASE userdb OWNER root;"


# ! stop other docker containers
stop_containers:
	echo "Stopping other docker containers"
	if [ $$(docker ps -q) ]; then \
		echo "Found and stopped docker containers..."; \
		docker stop $$(docker ps -q); \
	else \
		echo "No active containers found..."; \
	fi


# ! start docker container 
start-docker:
	docker start ${DB_DOCKER_CONTAINER}

create_migrations:
	sqlx migrate add -r init

migrate-up:
	sqlx migrate run --database-url "postgres://root:secret@localhost:5432/userdb?sslmode=disable"

migrate-down:
	sqlx migrate revert --database-url "postgres://root:secret@localhost:5432/userdb?sslmode=disable"

build:
	@echo "Building backend api binary"
	go build -o ${BINARY_NAME} cmd/server/*.go
	@echo "Binary built!"

run: build stop_containers start-docker
	@echo "Startin api"
	@env PORT=${PORT} DSN=${DSN} ./${BINARY_NAME} &
	@echo "api started!"

stop:
	@echo "Stopping backend"
	@-pkill -SIGTERM -f "./${BINARY_NAME}"
	@echo "Stopped backend"

start: run

restart: stop start

抱歉,我正在尽最大努力解决这个问题……请帮帮我。我正在学习Go语言和PostgreSQL。


更多关于Golang连接数据库时报错:无法连接到`host=localhost user=root database=userdb`(意外EOF导致消息接收失败)的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

欢迎来到论坛。

乍看之下,您可能需要通过向 docker run 命令添加 --network host 来将容器暴露给主机的网络。

// 代码示例(如有)

更多关于Golang连接数据库时报错:无法连接到`host=localhost user=root database=userdb`(意外EOF导致消息接收失败)的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


谢谢,它起作用了……我现在明白问题所在了。

这个错误通常是由于数据库连接配置问题导致的。以下是几个可能的解决方案:

1. 检查数据库连接字符串格式

你的DSN格式可能有问题,尝试使用以下格式:

// 修改Makefile中的DSN
DSN="postgres://root:secret@localhost:5432/userdb?sslmode=disable&connect_timeout=5"

或者在代码中直接使用:

func main() {
    // 使用pgx格式的DSN
    dsn := "postgres://root:secret@localhost:5432/userdb?sslmode=disable&connect_timeout=5"
    
    db, err := ConnectPostgres(dsn)
    if err != nil {
        log.Fatal("无法连接到数据库:", err)
    }
    defer db.DB.Close()
}

2. 确保数据库容器正在运行

添加一个检查数据库是否可用的函数:

package db

import (
    "context"
    "database/sql"
    "fmt"
    "time"
)

func ConnectPostgres(dsn string) (*DB, error) {
    // 先尝试ping数据库,最多重试5次
    var d *sql.DB
    var err error
    
    for i := 0; i < 5; i++ {
        d, err = sql.Open("pgx", dsn)
        if err != nil {
            time.Sleep(2 * time.Second)
            continue
        }
        
        ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
        defer cancel()
        
        if err = d.PingContext(ctx); err == nil {
            break
        }
        
        time.Sleep(2 * time.Second)
    }
    
    if err != nil {
        return nil, fmt.Errorf("连接数据库失败: %v", err)
    }
    
    d.SetMaxOpenConns(maxOpenDbConn)
    d.SetMaxIdleConns(maxIdleDbConn)
    d.SetConnMaxLifetime(maxDbLifeTime)
    
    dbConn.DB = d
    return dbConn, nil
}

3. 修改main.go确保正确初始化数据库

package main

import (
    "fmt"
    "log"
    "net/http"
    "os"
    "time"
    
    "github.com/jmechavez/PSO-Sarangani/db"
)

type Config struct {
    Port string
    DSN  string
}

type Application struct {
    Config Config
    Models db.DB
}

var port = os.Getenv("PORT")
var dsn = os.Getenv("DSN")

func main() {
    cfg := Config{
        Port: port,
        DSN:  dsn,
    }
    
    app := &Application{
        Config: cfg,
    }
    
    // 连接数据库
    log.Println("正在连接数据库...")
    database, err := db.ConnectPostgres(cfg.DSN)
    if err != nil {
        log.Fatal("无法连接到数据库:", err)
    }
    app.Models = *database
    
    log.Println("数据库连接成功!")
    
    // 启动服务器
    srv := &http.Server{
        Addr:         fmt.Sprintf(":%s", cfg.Port),
        IdleTimeout:  time.Minute,
        ReadTimeout:  10 * time.Second,
        WriteTimeout: 30 * time.Second,
    }
    
    log.Printf("API监听端口 %s", cfg.Port)
    if err := srv.ListenAndServe(); err != nil {
        log.Fatal(err)
    }
}

4. 添加一个简单的健康检查端点验证数据库连接

func (app *Application) healthCheck(w http.ResponseWriter, r *http.Request) {
    // 检查数据库连接
    err := app.Models.DB.Ping()
    if err != nil {
        http.Error(w, "数据库连接失败: "+err.Error(), http.StatusServiceUnavailable)
        return
    }
    
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusOK)
    fmt.Fprintf(w, `{"status": "healthy", "database": "connected"}`)
}

5. 确保正确导入驱动

修改db.go的导入部分:

package db

import (
    "database/sql"
    "fmt"
    "time"
    
    _ "github.com/jackc/pgx/v4/stdlib" // 只保留这个
)

6. 运行前手动验证数据库连接

在运行应用前,先验证数据库是否可用:

# 检查容器状态
docker ps | grep psosarangani_db

# 进入容器测试连接
docker exec -it psosarangani_db psql -U root -d userdb -c "SELECT 1;"

# 如果容器未运行,启动它
docker start psosarangani_db

# 等待几秒让数据库完全启动
sleep 5

主要问题可能是:

  1. 数据库容器未启动或启动不完全
  2. 连接字符串格式问题
  3. 网络连接问题(localhost vs 容器网络)

尝试这些修改后,应该能解决"意外EOF"的错误。

回到顶部