Let's Go پاسخ‌های مبتنی بر پایگاه داده › ایجاد استخر اتصال پایگاه داده
قبلی · فهرست · بعدی
فصل 4.4.

ایجاد استخر اتصال پایگاه داده

حالا که پایگاه داده MySQL کاملاً راه‌اندازی شده و یک درایور نصب کرده‌ایم، گام طبیعی بعدی اتصال به پایگاه داده از برنامه وب ما است.

برای انجام این کار به تابع sql.Open() Go نیاز داریم، که آن را کمی مانند این استفاده می‌کنید:

// The sql.Open() function initializes a new sql.DB object, which is essentially a
// pool of database connections.
db, err := sql.Open("mysql", "web:pass@/snippetbox?parseTime=true")
if err != nil {
    ...
}

چند نکته در مورد این کد برای توضیح و تأکید وجود دارد:

استفاده از آن در برنامه وب ما

بیایید نحوه استفاده از sql.Open() در عمل را ببینیم. فایل main.go خود را باز کنید و کد زیر را اضافه کنید:

File: cmd/web/main.go
package main

import (
    "database/sql" // New import
    "flag"
    "log/slog"
    "net/http"
    "os"

    _ "github.com/go-sql-driver/mysql" // New import
)

...

func main() {
    addr := flag.String("addr", ":4000", "HTTP network address")
    // Define a new command-line flag for the MySQL DSN string.
    dsn := flag.String("dsn", "web:pass@/snippetbox?parseTime=true", "MySQL data source name")
    flag.Parse()

    logger := slog.New(slog.NewTextHandler(os.Stdout, nil))

    // To keep the main() function tidy I've put the code for creating a connection
    // pool into the separate openDB() function below. We pass openDB() the DSN
    // from the command-line flag.
    db, err := openDB(*dsn)
    if err != nil {
        logger.Error(err.Error())
        os.Exit(1)
    }

    // We also defer a call to db.Close(), so that the connection pool is closed
    // before the main() function exits.
    defer db.Close()

    app := &application{
        logger: logger,
    }

    logger.Info("starting server", "addr", *addr)

    // Because the err variable is now already declared in the code above, we need
    // to use the assignment operator = here, instead of the := 'declare and assign'
    // operator.
    err = http.ListenAndServe(*addr, app.routes())
    logger.Error(err.Error())
    os.Exit(1)
}

// The openDB() function wraps sql.Open() and returns a sql.DB connection pool
// for a given DSN.
func openDB(dsn string) (*sql.DB, error) {
    db, err := sql.Open("mysql", dsn)
    if err != nil {
        return nil, err
    }

    err = db.Ping()
    if err != nil {
        db.Close()
        return nil, err
    }

    return db, nil
}

چند نکته جالب در مورد این کد وجود دارد:

تست یک اتصال

مطمئن شوید که فایل ذخیره شده است، و سپس سعی کنید برنامه را اجرا کنید. اگر همه چیز طبق برنامه پیش رفته باشد، استخر اتصال باید ایجاد شود و متد db.Ping() باید بتواند یک اتصال بدون هیچ خطایی ایجاد کند. اگر همه چیز خوب باشد، باید پیام لاگ عادی starting server را مانند این ببینید:

$ go run ./cmd/web
time=2024-03-18T11:29:23.000+00:00 level=INFO msg="starting server" addr=:4000

اگر برنامه راه‌اندازی نشود و یک پیام خطای "Access denied..." مانند زیر دریافت کنید، احتمالاً مشکل در DSN شما است. دوباره بررسی کنید که نام کاربری و رمز عبور صحیح هستند، که کاربران پایگاه داده شما مجوزهای مناسب دارند، و که نمونه MySQL شما از تنظیمات استاندارد استفاده می‌کند.

$ go run ./cmd/web
time=2024-03-18T11:29:23.000+00:00 level=ERROR msg="Error 1045 (28000): Access denied for user 'web'@'localhost' (using password: YES)"
exit status 1

مرتب کردن فایل go.mod

حالا که کد ما در واقع درایور github.com/go-sql-driver/mysql را import می‌کند، می‌توانید دستور go mod tidy را اجرا کنید تا فایل go.mod خود را مرتب کنید و هر حاشیه‌نویسی غیرضروری // indirect را حذف کنید.

$ go mod tidy

پس از انجام این کار، فایل go.mod شما باید اکنون مانند زیر به نظر برسد — با github.com/go-sql-driver/mysql به عنوان یک وابستگی مستقیم فهرست شده و filippo.io/edwards25519 همچنان یک وابستگی غیرمستقیم باشد.

File: go.mod
module snippetbox.alexedwards.net

go 1.23.0

require github.com/go-sql-driver/mysql v1.8.1

require filippo.io/edwards25519 v1.1.0 // indirect