ChatGPT Image Aug 5, 2026, 07_46_26 PM

آموزش اتصال سرور MTA به MySQL و رفع خطاهای دیتابیس

بسیاری از گیم‌مودها و Resourceهای حرفه‌ای MTA برای ذخیره اطلاعات بازیکنان، حساب‌ها، خودروها، خانه‌ها، موجودی، تنظیمات و گزارش‌ها به دیتابیس MySQL نیاز دارند.

اتصال اشتباه به دیتابیس می‌تواند باعث اجرا نشدن گیم‌مود، خطای ورود کاربران، ذخیره نشدن اطلاعات، کندی سرور یا نمایش پیام‌هایی مانند Access Denied و Can’t connect to MySQL server شود.

در این آموزش مراحل ساخت دیتابیس، ایجاد کاربر MySQL، واردکرد کاربر MySQL، واردکردن فایل SQL، اتصال سرور MTA با dbConnect، اجرای کوئری‌های ایمن و رفع خطاهای رایج را بررسی می‌کنیم.

برای اتصال MTA به MySQL چه چیزهایی لازم است؟

قبل از شروع، این اطلاعات و دسترسی‌ها باید آماده باشند:

  • یک سرور MTA فعال
  • دسترسی به فایل‌های Resource
  • سرور MySQL یا MariaDB
  • نام دیتابیس
  • نام کاربری دیتابیس
  • رمز کاربری دیتابیس
  • آدرس Host دیتابیس
  • پورت MySQL
  • فایل SQL گیم‌مود در صورت وجود
  • اجازه اتصال از IP سرور MTA

پورت پیش‌فرض MySQL معمولاً 3306 است؛ اما ممکن است شرکت میزبان یا مدیر سرور آن را تغییر داده باشد.

اطلاعات اصلی اتصال به دیتابیس

مقدار نمونه توضیح
Host 127.0.0.1 آدرس سرور MySQL
Port 3306 پورت سرویس MySQL
Database kimia_mta نام دیتابیس پروژه
Username kimia_mta_user کاربر دارای دسترسی به دیتابیس
Password رمز قوی رمز اختصاصی کاربر دیتابیس
Charset utf8mb4 کدگذاری مناسب متن فارسی و یونیکد

اطلاعات واقعی پروژه را به‌جای نمونه‌های این مقاله قرار دهید. رمز دیتابیس نباید داخل فایل‌های client-side یا shared قرار بگیرد.

دیتابیس روی همان VPS یا سرور جداگانه؟

اگر MySQL روی همان VPS سرور MTA نصب شده است، معمولاً می‌توان از آدرس زیر استفاده کرد:

127.0.0.1

اگر دیتابیس روی هاست یا سرور دیگری قرار دارد، باید IP یا نام Host همان سرور را وارد کنید:

db.example.com

در اتصال راه دور، سرور MySQL باید اتصال از IP سرور MTA را بپذیرد و پورت مربوط نیز در فایروال باز باشد.

پورت MySQL را بدون محدودیت برای تمام اینترنت باز نکنید. دسترسی شبکه را فقط به IP سرورهای موردنیاز محدود کنید.

ساخت دیتابیس در cPanel

در هاست‌های دارای cPanel معمولاً می‌توان دیتابیس را از بخش MySQL Databases یا Database Wizard ساخت.

  1. وارد cPanel شوید.
  2. بخش MySQL Databases را باز کنید.
  3. یک دیتابیس جدید بسازید.
  4. یک کاربر MySQL با رمز قوی ایجاد کنید.
  5. کاربر را به دیتابیس اضافه کنید.
  6. دسترسی‌های موردنیاز را برای کاربر فعال کنید.
  7. نام کامل دیتابیس و کاربر را یادداشت کنید.

در بسیاری از هاست‌های اشتراکی، نام حساب cPanel به ابتدای نام دیتابیس و کاربر اضافه می‌شود.

برای مثال ممکن است نامی که وارد کرده‌اید:

mta

در نهایت به‌شکل زیر ثبت شود:

accountname_mta

در dbConnect باید نام کامل نمایش‌داده‌شده در cPanel را استفاده کنید.

ساخت دیتابیس با دستورات MySQL

اگر دسترسی مدیریتی MySQL دارید، می‌توان دیتابیس را با دستورهای SQL ساخت. نام‌ها و رمز نمونه را تغییر دهید:

CREATE DATABASE `kimia_mta`
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;

CREATE USER 'kimia_mta_user'@'127.0.0.1'
IDENTIFIED BY 'CHANGE-THIS-STRONG-PASSWORD';

GRANT SELECT, INSERT, UPDATE, DELETE
ON `kimia_mta`.*
TO 'kimia_mta_user'@'127.0.0.1';

FLUSH PRIVILEGES;

اگر Resource در زمان نصب جدول‌ها را ایجاد یا ساختار آن‌ها را تغییر می‌دهد، ممکن است موقتاً به Permissionهای دیگری مانند CREATE، ALTER یا INDEX نیاز داشته باشد.

بعد از نصب و واردکردن ساختار دیتابیس، بهتر است دسترسی کاربر اجرایی براساس نیاز واقعی پروژه محدود شود.

تفاوت کاربر localhost و کاربر IP

در MySQL نام کاربر همراه با Host مجاز آن تعریف می‌شود. این دو حساب ممکن است دسترسی متفاوتی داشته باشند:

'kimia_mta_user'@'localhost'
'kimia_mta_user'@'127.0.0.1'

برای اتصال راه دور نیز ممکن است کاربر فقط برای IP سرور MTA تعریف شود:

'kimia_mta_user'@'IP-SERVER-MTA'

اگر نام کاربری و رمز صحیح هستند اما Access Denied دریافت می‌شود، Host مجاز حساب MySQL را نیز بررسی کنید.

واردکردن فایل SQL گیم‌مود

بسیاری از گیم‌مودها همراه فایل SQL ارائه می‌شوند. این فایل ممکن است جدول‌های کاربران، خودروها، خانه‌ها، مشاغل و تنظیمات اولیه را ایجاد کند.

برای Import در phpMyAdmin:

  1. وارد phpMyAdmin شوید.
  2. دیتابیس ساخته‌شده را انتخاب کنید.
  3. به بخش Import بروید.
  4. فایل دارای پسوند sql را انتخاب کنید.
  5. Character Set را در صورت نیاز روی UTF-8 قرار دهید.
  6. عملیات Import را اجرا کنید.
  7. ایجاد جدول‌ها را بررسی کنید.

بعد از Import باید جدول‌های پروژه در بخش Structure دیتابیس دیده شوند.

Import فایل SQL از طریق خط فرمان

در سرور لینوکس و با دسترسی مناسب می‌توان فایل SQL را با دستور زیر وارد کرد:

mysql -u kimia_mta_user -p kimia_mta < database.sql

پس از اجرای دستور، رمز کاربر MySQL درخواست می‌شود.

اگر MySQL روی Host یا پورت دیگری قرار دارد:

mysql -h DATABASE-HOST -P 3306 -u kimia_mta_user -p kimia_mta < database.sql

قبل از Import فایل SQL چه چیزهایی را بررسی کنیم؟

  • فایل SQL متعلق به همان نسخه گیم‌مود باشد.
  • از دیتابیس فعلی نسخه پشتیبان تهیه شده باشد.
  • نام جدول‌های موجود با فایل جدید تداخل نداشته باشد.
  • Character Set فایل مشخص باشد.
  • حجم فایل از محدودیت Upload هاست بیشتر نباشد.
  • فایل شامل دستور حذف ناخواسته جدول‌ها نباشد.
  • اطلاعات نمونه یا حساب‌های پیش‌فرض بررسی شوند.

ساختار Resource اتصال دیتابیس

بهتر است اتصال دیتابیس در یک Resource یا فایل server-side جداگانه مدیریت شود.

mysql_connection/
├── meta.xml
├── database_config.lua
├── database.lua
└── example.lua

فایل‌های حاوی رمز دیتابیس باید فقط با type=”server” تعریف شوند.

نمونه فایل meta.xml

<meta>
    <info
        author="KimiaGame"
        name="MySQL Connection"
        version="1.0.0"
        type="script"
    />

    <script src="database_config.lua" type="server" />
    <script src="database.lua" type="server" />
    <script src="example.lua" type="server" />
</meta>

فایل database_config.lua قبل از database.lua بارگذاری می‌شود تا متغیرهای اتصال در دسترس باشند.

ساخت فایل تنظیمات دیتابیس

داخل فایل database_config.lua اطلاعات اتصال را وارد کنید:

DB_HOST = "127.0.0.1"
DB_PORT = 3306
DB_NAME = "kimia_mta"
DB_USER = "kimia_mta_user"
DB_PASSWORD = "CHANGE-THIS-STRONG-PASSWORD"

این فایل نباید به‌صورت client یا shared در meta.xml ثبت شود.

اطلاعات واقعی دیتابیس را در مخزن عمومی، گروه‌های گفتگو یا تصاویر آموزشی منتشر نکنید.

اتصال MTA به MySQL با dbConnect

داخل فایل database.lua می‌توان اتصال را هنگام شروع Resource ایجاد کرد:

DB = false

local function connectToDatabase()
    local connectionString = string.format(
        "dbname=%s;host=%s;port=%d;charset=utf8mb4",
        DB_NAME,
        DB_HOST,
        DB_PORT
    )

    DB = dbConnect(
        "mysql",
        connectionString,
        DB_USER,
        DB_PASSWORD,
        "share=0;autoreconnect=1;tag=kimia_mta"
    )

    if DB then
        outputDebugString(
            "[MySQL] Connection established successfully.",
            3
        )
    else
        outputDebugString(
            "[MySQL] Failed to connect to the database.",
            1
        )
    end
end

addEventHandler(
    "onResourceStart",
    resourceRoot,
    connectToDatabase
)

اگر اتصال موفق باشد، dbConnect یک Database Connection Element برمی‌گرداند. درصورت شکست، مقدار false دریافت می‌شود.

چرا dbConnect را فقط یک‌بار اجرا کنیم؟

ایجاد و بستن مداوم اتصال دیتابیس می‌تواند مصرف منابع و زمان پاسخ‌گویی را افزایش دهد.

روش مناسب این است که:

  • اتصال هنگام شروع Resource ساخته شود.
  • همان Connection Element برای تمام کوئری‌های Resource استفاده شود.
  • برای هر ورود بازیکن اتصال جدید ایجاد نشود.
  • برای هر کوئری dbConnect جداگانه اجرا نشود.

اگر Resource متوقف شود، Elementهای متعلق به آن Resource نیز مدیریت می‌شوند. درصورت نیاز می‌توان اتصال را با destroyElement بست.

آزمایش ساده اتصال دیتابیس

بعد از اجرای Resource، پیام موفقیت یا شکست را در کنسول سرور بررسی کنید.

برای اجرای Resource:

refresh
start mysql_connection

برای اجرای مجدد پس از تغییر اطلاعات اتصال:

restart mysql_connection

درصورت موفقیت باید پیام مشابه زیر در کنسول دیده شود:

[MySQL] Connection established successfully.

ساخت جدول آزمایشی با dbExec

dbExec برای کوئری‌هایی مناسب است که نیازی به دریافت جدول نتیجه ندارند؛ مانند CREATE، INSERT، UPDATE و DELETE.

local function createPlayersTable()
    if not DB then
        outputDebugString(
            "[MySQL] Database connection is not available.",
            1
        )
        return
    end

    local success = dbExec(DB, [[
        CREATE TABLE IF NOT EXISTS `players` (
            `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
            `serial` VARCHAR(64) NOT NULL,
            `username` VARCHAR(64) NOT NULL,
            `money` INT NOT NULL DEFAULT 0,
            `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY (`id`),
            UNIQUE KEY `unique_serial` (`serial`)
        )
        CHARACTER SET utf8mb4
        COLLATE utf8mb4_unicode_ci
    ]])

    if success then
        outputDebugString(
            "[MySQL] Players table query executed.",
            3
        )
    else
        outputDebugString(
            "[MySQL] Failed to execute table creation query.",
            1
        )
    end
end

addEventHandler(
    "onResourceStart",
    resourceRoot,
    function()
        setTimer(createPlayersTable, 500, 1)
    end
)

در پروژه واقعی بهتر است ساختار جدول‌ها با فایل SQL و سیستم Migration مشخص مدیریت شود.

ثبت اطلاعات با INSERT

برای ثبت بازیکن نمونه می‌توان از dbExec و Placeholder استفاده کرد:

function createPlayerRecord(serial, username)
    if not DB then
        return false
    end

    return dbExec(
        DB,
        "INSERT INTO `players` (`serial`, `username`) VALUES (?, ?)",
        serial,
        username
    )
end

مقادیر serial و username به‌جای علامت‌های سؤال قرار می‌گیرند. این روش از ساخت مستقیم کوئری با چسباندن رشته‌ها ایمن‌تر است.

روش اشتباه ساخت کوئری

این روش مناسب نیست:

local query = "SELECT * FROM players WHERE username = '" .. username .. "'"

قرار دادن مستقیم ورودی کاربران داخل متن SQL می‌تواند باعث خراب‌شدن کوئری یا ایجاد خطر SQL Injection شود.

نسخه مناسب‌تر:

dbQuery(
    callbackFunction,
    DB,
    "SELECT * FROM `players` WHERE `username` = ? LIMIT 1",
    username
)

دریافت اطلاعات با dbQuery

dbQuery یک Query Handle ایجاد می‌کند. برای دریافت نتیجه باید از dbPoll استفاده شود.

روش پیشنهادی، اجرای غیرهم‌زمان کوئری و پردازش نتیجه داخل Callback است:

function loadPlayerBySerial(player, serial)
    if not DB then
        outputDebugString(
            "[MySQL] Database connection is not available.",
            1
        )
        return
    end

    dbQuery(
        function(queryHandle, targetPlayer)
            local rows, errorCode, errorMessage =
                dbPoll(queryHandle, 0)

            if rows == false then
                outputDebugString(
                    "[MySQL] Query failed. Code: "
                    .. tostring(errorCode)
                    .. " Message: "
                    .. tostring(errorMessage),
                    1
                )
                return
            end

            if not isElement(targetPlayer) then
                return
            end

            if #rows == 0 then
                outputChatBox(
                    "اطلاعاتی برای این بازیکن پیدا نشد.",
                    targetPlayer,
                    255,
                    180,
                    0
                )
                return
            end

            local playerData = rows[1]

            outputChatBox(
                "نام ثبت‌شده: "
                .. tostring(playerData.username),
                targetPlayer,
                0,
                255,
                0
            )
        end,
        {player},
        DB,
        "SELECT `id`, `username`, `money` FROM `players` WHERE `serial` = ? LIMIT 1",
        serial
    )
end

در این نمونه، اجرای اصلی سرور منتظر پایان کوئری نمی‌ماند. پس از آماده‌شدن نتیجه، Callback اجرا می‌شود.

چرا نباید از dbPoll با مقدار منفی استفاده کنیم؟

این نمونه نتیجه را به‌صورت هم‌زمان دریافت می‌کند:

local queryHandle =
    dbQuery(DB, "SELECT * FROM `players`")

local result =
    dbPoll(queryHandle, -1)

مقدار -1 باعث می‌شود کل سرور تا آماده‌شدن نتیجه منتظر بماند. اگر دیتابیس کند یا اتصال دچار اختلال باشد، اجرای گیم‌مود نیز متوقف می‌شود.

برای کوئری‌های معمول سرور فعال، استفاده از Callback غیرهم‌زمان مناسب‌تر است.

به‌روزرسانی اطلاعات با UPDATE

function updatePlayerMoney(serial, newMoney)
    if not DB then
        return false
    end

    return dbExec(
        DB,
        "UPDATE `players` SET `money` = ? WHERE `serial` = ?",
        tonumber(newMoney) or 0,
        serial
    )
end

قبل از ثبت اطلاعات عددی، نوع مقدار را بررسی کنید. داده دریافتی از کلاینت نباید بدون اعتبارسنجی وارد دیتابیس شود.

حذف اطلاعات با DELETE

function deletePlayerRecord(serial)
    if not DB then
        return false
    end

    return dbExec(
        DB,
        "DELETE FROM `players` WHERE `serial` = ?",
        serial
    )
end

قبل از اجرای DELETE روی اطلاعات واقعی، شرط WHERE را دقیق بررسی و از دیتابیس نسخه پشتیبان تهیه کنید.

استفاده از اتصال دیتابیس در چند Resource

در پروژه‌های بزرگ می‌توان یک Resource مرکزی برای دیتابیس ساخت و Connection Element را از طریق Export در اختیار سایر Resourceها قرار داد.

در meta.xml مربوط به Resource دیتابیس:

<export function="getDatabaseConnection" type="server" />

در database.lua:

function getDatabaseConnection()
    return DB
end

در Resource دیگر:

local connection =
    exports.mysql_connection:getDatabaseConnection()

if connection then
    dbExec(
        connection,
        "UPDATE `players` SET `money` = ? WHERE `serial` = ?",
        5000,
        playerSerial
    )
end

Resource دیتابیس باید قبل از Resourceهای وابسته اجرا شده باشد.

تعریف وابستگی Resource دیتابیس

در meta.xml یک Resource وابسته می‌توان از include استفاده کرد:

<meta>
    <include resource="mysql_connection" />
    <script src="server.lua" type="server" />
</meta>

اگر Resource اتصال دیتابیس اجرا نشود، Resourceهای وابسته نیز ممکن است نتوانند فعالیت خود را شروع کنند.

تنظیم utf8mb4 برای متن فارسی

برای ذخیره صحیح متن فارسی و کاراکترهای یونیکد بهتر است دیتابیس، جدول‌ها و اتصال از utf8mb4 استفاده کنند.

در رشته اتصال:

charset=utf8mb4

در ساخت دیتابیس:

CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci

در ساخت جدول:

CREATE TABLE `messages` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `message` TEXT NOT NULL,
    PRIMARY KEY (`id`)
)
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;

چرا متن فارسی به علامت سؤال تبدیل می‌شود؟

دلایل معمول عبارت‌اند از:

  • Character Set دیتابیس مناسب نیست.
  • جدول یا ستون با latin1 ساخته شده است.
  • رشته اتصال charset صحیح ندارد.
  • فایل SQL با Encoding اشتباه ذخیره شده است.
  • اطلاعات قبلاً به‌صورت خراب وارد شده‌اند.
  • Collation جدول‌ها با ساختار پروژه هماهنگ نیست.

تغییر Character Set همیشه اطلاعات خراب قبلی را بازیابی نمی‌کند. قبل از تبدیل جدول‌های فعال، بکاپ کامل تهیه کنید.

فعال‌کردن گزارش دیتابیس با debugdb

برای ثبت خطاها و کوئری‌های دیتابیس، در کنسول اصلی سرور دستور زیر را اجرا کنید:

debugdb 2

خروجی معمولاً در این فایل ذخیره می‌شود:

mods/deathmatch/logs/db.log

سطوح debugdb:

دستور خروجی
debugdb 0 خاموش‌کردن گزارش دیتابیس
debugdb 1 ثبت خطاها
debugdb 2 ثبت کامل فعالیت کوئری‌ها

سطح 2 ممکن است فایل Log بزرگی تولید کند. پس از پایان عیب‌یابی، آن را روی سطح مناسب برگردانید.

بررسی خطاهای Resource با debugscript

علاوه بر debugdb، خطاهای Lua را نیز بررسی کنید:

debugscript 3

اگر DB مقدار false دارد یا تابعی با Connection نامعتبر اجرا می‌شود، خطای مربوط در Debug نمایش داده خواهد شد.

خطای Access denied for user

این خطا معمولاً با کد 1045 دیده می‌شود و نشان می‌دهد MySQL اتصال کاربر را قبول نکرده است.

موارد زیر را بررسی کنید:

  • نام کاربری دیتابیس صحیح باشد.
  • رمز عبور دقیق وارد شده باشد.
  • حروف بزرگ و کوچک رمز تغییر نکرده باشند.
  • کاربر برای Host یا IP صحیح ساخته شده باشد.
  • کاربر به دیتابیس موردنظر متصل شده باشد.
  • نام کامل کاربر cPanel استفاده شده باشد.
  • فاصله اضافی در اطلاعات اتصال وجود نداشته باشد.

در اتصال راه دور، کاربر localhost الزاماً اجازه اتصال از IP سرور MTA را ندارد.

خطای Access denied to database

ممکن است کاربر بتواند به MySQL متصل شود اما اجازه استفاده از دیتابیس انتخاب‌شده را نداشته باشد.

  • کاربر را به دیتابیس موردنظر اضافه کنید.
  • Permissionهای لازم را فعال کنید.
  • نام دیتابیس داخل dbConnect را بررسی کنید.
  • پیشوند حساب cPanel را فراموش نکنید.
  • GRANTهای حساب را بررسی کنید.

خطای Can’t connect to MySQL server

این خطا معمولاً به مشکل شبکه، Host، پورت یا اجرا نبودن سرویس MySQL مربوط است.

  • سرویس MySQL یا MariaDB در حال اجرا باشد.
  • آدرس Host صحیح باشد.
  • پورت اتصال صحیح باشد.
  • فایروال اتصال را مسدود نکرده باشد.
  • Remote MySQL فعال باشد.
  • MySQL روی آدرس شبکه مناسب Listen کند.
  • IP سرور MTA در فهرست مجاز قرار داشته باشد.
  • مسیر شبکه میان دو سرور برقرار باشد.

در اتصال محلی، استفاده از 127.0.0.1 به‌جای یک آدرس نامعتبر می‌تواند مسیر اتصال TCP را مشخص‌تر کند.

خطای Unknown database

این پیام نشان می‌دهد دیتابیسی با نام ثبت‌شده در رشته اتصال پیدا نشده است.

  • وجود دیتابیس را در phpMyAdmin بررسی کنید.
  • نام داخل DB_NAME را اصلاح کنید.
  • پیشوند cPanel را بررسی کنید.
  • فاصله یا کاراکتر اضافی را حذف کنید.
  • مطمئن شوید به سرور MySQL صحیح متصل شده‌اید.

خطای Table doesn’t exist

در این حالت اتصال برقرار است، اما جدول موردنظر داخل دیتابیس وجود ندارد.

  • فایل SQL را Import کنید.
  • دیتابیس صحیح را انتخاب کنید.
  • نام جدول را بررسی کنید.
  • حروف بزرگ و کوچک نام جدول را در لینوکس بررسی کنید.
  • نسخه فایل SQL را با نسخه گیم‌مود تطبیق دهید.
  • پیشوند جدول‌ها را بررسی کنید.

خطای Column doesn’t exist

این خطا معمولاً زمانی دیده می‌شود که ساختار دیتابیس قدیمی‌تر یا جدیدتر از کد Resource باشد.

  • نام ستون در کوئری را بررسی کنید.
  • فایل Migration یا Update دیتابیس را اجرا کنید.
  • نسخه گیم‌مود و SQL را هماهنگ کنید.
  • از تغییر دستی نام ستون‌ها بدون بررسی خودداری کنید.
  • قبل از ALTER TABLE بکاپ بگیرید.

خطای MySQL server has gone away

این خطا می‌تواند به قطع اتصال، ری‌استارت MySQL، Timeout، بسته بزرگ یا اختلال شبکه مربوط باشد.

  • وضعیت سرویس MySQL را بررسی کنید.
  • اتصال شبکه را آزمایش کنید.
  • حجم کوئری و داده ارسالی را کاهش دهید.
  • تنظیمات Timeout سرور را بررسی کنید.
  • حجم max_allowed_packet را درصورت نیاز بررسی کنید.
  • از اجرای کوئری‌های بسیار بزرگ در یک مرحله خودداری کنید.
  • Logهای MySQL و db.log را بررسی کنید.

گزینه autoreconnect در dbConnect می‌تواند اتصال قطع‌شده را دوباره برقرار کند؛ اما وضعیت‌هایی مانند Temporary Table، متغیر Session و Lockها پس از اتصال مجدد باقی نمی‌مانند.

خطای Too many connections

این خطا زمانی ایجاد می‌شود که تعداد اتصال‌های فعال MySQL از محدودیت سرور عبور کند.

  • dbConnect را برای هر بازیکن اجرا نکنید.
  • برای هر کوئری اتصال جدید نسازید.
  • Resourceهای مختلف را از نظر اتصال‌های تکراری بررسی کنید.
  • اتصال‌های رهاشده برنامه‌های دیگر را بررسی کنید.
  • محدودیت max_connections سرور را ارزیابی کنید.

در بیشتر گیم‌مودها یک اتصال پایدار یا یک سیستم مرکزی Connection برای هر پروژه کافی است.

مشکل MySQL 8 و روش احراز هویت

MySQL 8 می‌تواند از روش‌های احراز هویت جدید مانند caching_sha2_password استفاده کند. نسخه‌های جدید MTA گزینه‌های مربوط به دریافت Public Key و اتصال با این روش را پشتیبانی می‌کنند.

درصورت خطای احراز هویت:

  • نسخه MTA Server را بررسی و بروزرسانی کنید.
  • نوع Authentication Plugin کاربر MySQL را بررسی کنید.
  • پیام دقیق خطا را از db.log بخوانید.
  • از تغییر ناامن روش احراز هویت بدون بررسی خودداری کنید.
  • تنظیمات SSL و Public Key را با نسخه MySQL هماهنگ کنید.

چرا اتصال برقرار است اما گیم‌مود کار نمی‌کند؟

موفقیت dbConnect فقط اتصال اولیه را تأیید می‌کند. ممکن است گیم‌مود به دلایل دیگری کار نکند:

  • جدول‌ها Import نشده‌اند.
  • نام جدول‌ها با کد تطبیق ندارد.
  • ستون‌های لازم وجود ندارند.
  • Resource دیتابیس قبل از گیم‌مود اجرا نشده است.
  • Export اتصال اشتباه است.
  • کوئری SQL دارای Syntax Error است.
  • کاربر Permission کافی ندارد.
  • نتیجه dbQuery درست پردازش نمی‌شود.
  • کد از dbPoll با روش نامناسب استفاده می‌کند.

بهینه‌سازی کوئری‌های دیتابیس MTA

دیتابیس کند می‌تواند باعث تأخیر در ورود بازیکنان، ذخیره اطلاعات و اجرای سیستم‌های گیم‌مود شود.

  • کوئری‌های SELECT را غیرهم‌زمان اجرا کنید.
  • فقط ستون‌های موردنیاز را دریافت کنید.
  • به‌جای SELECT * ستون‌ها را مشخص کنید.
  • برای ستون‌های جست‌وجوشونده Index مناسب ایجاد کنید.
  • از اجرای کوئری داخل Loopهای بزرگ خودداری کنید.
  • اطلاعات ثابت را در صورت امکان Cache کنید.
  • کوئری را چند بار پشت‌سرهم اجرا نکنید.
  • ذخیره اطلاعات را در بازه منطقی انجام دهید.
  • از Placeholder برای مقادیر استفاده کنید.
  • کوئری‌های کند را با debugdb بررسی کنید.

استفاده از Index در جدول‌ها

اگر بازیکن دائماً با serial جست‌وجو می‌شود، این ستون باید Index مناسب داشته باشد:

ALTER TABLE `players`
ADD UNIQUE KEY `unique_serial` (`serial`);

برای ستون نام کاربری نیز در صورت نیاز می‌توان Index ایجاد کرد:

ALTER TABLE `players`
ADD INDEX `index_username` (`username`);

ایجاد Index برای تمام ستون‌ها مناسب نیست. Index باید بر اساس کوئری‌های واقعی پروژه طراحی شود.

اشتباهات رایج در اتصال MTA به MySQL

  • نوشتن نام ناقص دیتابیس cPanel
  • استفاده از کاربر MySQL بدون Permission
  • قرار دادن رمز در client.lua
  • ساخت اتصال برای هر بازیکن
  • اجرای dbPoll با مقدار -1 در سرور فعال
  • چسباندن مستقیم ورودی کاربر به SQL
  • Import نکردن فایل SQL
  • استفاده از Host اشتباه
  • بازکردن پورت 3306 برای همه IPها
  • هماهنگ نبودن Character Set
  • اجرا نشدن Resource دیتابیس قبل از گیم‌مود
  • نداشتن بکاپ قبل از تغییر جدول‌ها
  • ثبت Log کامل برای مدت طولانی

نکات امنیتی دیتابیس گیم‌سرور

  • برای MTA کاربر MySQL جداگانه ایجاد کنید.
  • از حساب root در گیم‌مود استفاده نکنید.
  • Permissionها را به دیتابیس همان پروژه محدود کنید.
  • رمز قوی و اختصاصی انتخاب کنید.
  • رمز را فقط در فایل server-side نگه دارید.
  • اتصال Remote را فقط برای IP موردنیاز باز کنید.
  • ورودی‌های کلاینت را اعتبارسنجی کنید.
  • از Placeholder در کوئری‌ها استفاده کنید.
  • از دیتابیس بکاپ دوره‌ای بگیرید.
  • Resourceهای ناشناس را قبل از اجرا بررسی کنید.
  • فایل‌های Log را از نظر اطلاعات حساس بررسی کنید.

بکاپ گرفتن از دیتابیس

برای تهیه نسخه پشتیبان از طریق خط فرمان:

mysqldump -u kimia_mta_user -p kimia_mta > kimia_mta_backup.sql

برای دیتابیس راه دور:

mysqldump -h DATABASE-HOST -P 3306 -u kimia_mta_user -p kimia_mta > kimia_mta_backup.sql

نسخه‌های بکاپ را فقط روی همان VPS نگهداری نکنید. حداقل یک نسخه در فضای جداگانه و امن ذخیره شود.

ترتیب عملی اتصال MTA به MySQL

  1. MySQL یا MariaDB را آماده کنید.
  2. دیتابیس جدید بسازید.
  3. کاربر اختصاصی ایجاد کنید.
  4. کاربر را به دیتابیس متصل کنید.
  5. دسترسی‌های لازم را فعال کنید.
  6. فایل SQL گیم‌مود را Import کنید.
  7. Host و پورت اتصال را بررسی کنید.
  8. اتصال Remote را در صورت نیاز محدود و فعال کنید.
  9. فایل server-side تنظیمات دیتابیس را بسازید.
  10. dbConnect را هنگام شروع Resource اجرا کنید.
  11. Resource را Start یا Restart کنید.
  12. پیام اتصال را در کنسول بررسی کنید.
  13. debugdb 2 را برای عیب‌یابی موقت فعال کنید.
  14. یک کوئری SELECT یا INSERT آزمایشی اجرا کنید.
  15. پس از تأیید، گیم‌مود اصلی را اجرا کنید.

جدول سریع عیب‌یابی اتصال MySQL

خطا علت احتمالی اقدام پیشنهادی
Access denied for user نام، رمز یا Host مجاز اشتباه اطلاعات کاربر و Host حساب را بررسی کنید
Access denied to database Permission دیتابیس وجود ندارد کاربر را به دیتابیس اضافه و GRANT را بررسی کنید
Can’t connect Host، پورت، فایروال یا سرویس شبکه و اجرای MySQL را بررسی کنید
Unknown database نام دیتابیس اشتباه DB_NAME و پیشوند cPanel را اصلاح کنید
Table doesn’t exist فایل SQL Import نشده ساختار دیتابیس را وارد کنید
Unknown column نسخه SQL و کد هماهنگ نیست Migration یا SQL صحیح را اجرا کنید
Server has gone away قطع اتصال، Timeout یا بسته بزرگ Log، شبکه و تنظیمات MySQL را بررسی کنید
Too many connections dbConnectهای پرتعداد اتصال مرکزی و پایدار ایجاد کنید
فارسی به‌هم‌ریخته Charset یا Collation اشتباه utf8mb4 را در اتصال و جدول‌ها تنظیم کنید
گیم‌مود کند است کوئری هم‌زمان یا بدون Index Callback غیرهم‌زمان و Index مناسب استفاده کنید

چک‌لیست نهایی

  • دیتابیس ایجاد شده است.
  • کاربر MySQL اختصاصی وجود دارد.
  • کاربر Permission لازم را دارد.
  • فایل SQL Import شده است.
  • نام جدول‌ها با گیم‌مود تطبیق دارد.
  • Host و Port صحیح هستند.
  • IP سرور MTA اجازه اتصال دارد.
  • پورت MySQL فقط برای IPهای لازم باز است.
  • رشته اتصال از utf8mb4 استفاده می‌کند.
  • رمز فقط در اسکریپت server-side است.
  • dbConnect فقط یک‌بار اجرا می‌شود.
  • کوئری‌های SELECT غیرهم‌زمان هستند.
  • از Placeholder استفاده شده است.
  • debugdb و debugscript بررسی شده‌اند.
  • از دیتابیس بکاپ وجود دارد.

جمع‌بندی

برای اتصال MTA به MySQL ابتدا باید دیتابیس و کاربر اختصاصی بسازید، فایل SQL پروژه را وارد کنید و سپس اطلاعات Host، Port، Database، Username و Password را در یک فایل server-side قرار دهید.

اتصال با dbConnect بهتر است فقط یک‌بار هنگام شروع Resource ساخته شود. برای دریافت اطلاعات نیز استفاده از dbQuery به‌صورت غیرهم‌زمان باعث می‌شود اجرای اصلی سرور منتظر دیتابیس نماند.

درصورت خطا، پیام‌های کنسول، debugscript و فایل logs/db.log را بررسی کنید. نام دیتابیس، Permission کاربر، Host مجاز، پورت، فایروال و ساختار جدول‌ها مهم‌ترین بخش‌های عیب‌یابی هستند.

برای نصب زیرساخت اولیه، مقاله آموزش ساخت سرور MTA روی VPS لینوکس را مطالعه کنید.

برای نصب و عیب‌یابی Resource نیز راهنمای آموزش نصب Resource در MTA و رفع خطاهای اجرا را ببینید.

اگر دیتابیس باعث کندی سرور شده است، مقاله علت لگ سرور MTA و روش‌های رفع آن را بررسی کنید.

برای بررسی اتصال، Import دیتابیس و رفع خطاهای پروژه می‌توانید از خدمات پشتیبانی فنی گیم‌سرور و راه‌اندازی و کانفیگ سرور MTA استفاده کنید.

پرسش‌های متداول

دستور اتصال MTA به MySQL چیست؟

اتصال با تابع dbConnect و نوع mysql ساخته می‌شود. رشته اتصال شامل نام دیتابیس، Host، Port و Charset است و نام کاربری و رمز نیز جداگانه به تابع داده می‌شوند.

چرا dbConnect مقدار false برمی‌گرداند؟

معمولاً اطلاعات اتصال اشتباه است، کاربر Permission ندارد، سرویس MySQL در دسترس نیست یا فایروال پورت اتصال را بسته است. debugdb 2 و db.log را بررسی کنید.

Host دیتابیس محلی را چه بگذاریم؟

اگر MySQL روی همان VPS اجرا می‌شود، معمولاً 127.0.0.1 مناسب است. در هاست جداگانه باید Host اعلام‌شده توسط شرکت میزبان وارد شود.

چرا اطلاعات فارسی خراب ذخیره می‌شوند؟

Charset رشته اتصال، دیتابیس، جدول و ستون‌ها را بررسی کنید. برای پروژه‌های جدید استفاده از utf8mb4 پیشنهاد می‌شود.

آیا می‌توان رمز دیتابیس را در client.lua قرار داد؟

خیر. فایل‌های client-side برای بازیکن ارسال می‌شوند. اطلاعات اتصال باید فقط در اسکریپت‌های type=”server” نگهداری شوند.

dbExec چه تفاوتی با dbQuery دارد؟

dbExec برای اجرای کوئری‌هایی استفاده می‌شود که نتیجه جدولی لازم ندارند. dbQuery یک Query Handle برمی‌گرداند و نتیجه آن با dbPoll دریافت می‌شود.

چرا استفاده از dbPoll با مقدار -1 مناسب نیست؟

زیرا سرور تا آماده‌شدن نتیجه منتظر می‌ماند. در دیتابیس کند یا اتصال ناپایدار، این انتظار می‌تواند اجرای کل گیم‌مود را متوقف کند.

چگونه کوئری‌های دیتابیس را مشاهده کنیم؟

در کنسول اصلی سرور دستور debugdb 2 را اجرا کنید. گزارش کامل معمولاً در فایل mods/deathmatch/logs/db.log ثبت می‌شود.

منابع رسمی مرتبط

Comments are closed.