วิธีเชื่อม FiveM กับ MySQL หรือ MariaDB ด้วย oxmysql แบบ Step-by-Step
การเชื่อม FiveM กับ MySQL หรือ MariaDB ด้วย oxmysql ต้องมี 3 ส่วนหลักคือ Database Server, Resource oxmysql และ mysql_connection_string ที่ถูกต้อง จากนั้น Resource FiveM ฝั่ง Server จึงสามารถใช้ MySQL.query, MySQL.single, MySQL.insert, MySQL.update หรือ API อื่นเพื่ออ่านและบันทึกข้อมูลได้
โครงสร้างคือ
FiveM Resource
↓
Server Script
↓
oxmysql
↓
Connection String
↓
MySQL / MariaDB
↓
Database
ตัวอย่าง server.cfg
set mysql_connection_string "mysql://fivem_user:password@127.0.0.1:3306/fivem"
ensure oxmysql
ensure my_resource
ตัวอย่าง fxmanifest.lua
fx_version 'cerulean'
game 'gta5'
dependency 'oxmysql'
server_script '@oxmysql/lib/MySQL.lua'
server_script 'server.lua'
และ server.lua
local result =
MySQL.scalar.await(
'SELECT 1'
)
print(
'Database test:',
result
)
ถ้าได้ค่า
1
แสดงว่า FiveM Resource สามารถส่ง Query ผ่าน oxmysql ไปยัง Database ได้แล้ว
① สิ่งที่ต้องเตรียมก่อนเชื่อม Database
ควรมี
① FXServer ที่ใช้งานได้
② MySQL หรือ MariaDB
③ Database สำหรับ FiveM
④ Database User
⑤ oxmysql
⑥ server.cfg
⑦ Resource ที่ต้องการใช้ Database
อย่าเริ่มเขียน SQL ใน Script ก่อนที่ Database Connection จะทำงาน
ควรทำให้
SELECT 1
ผ่านก่อน แล้วจึงสร้างระบบ Character, Garage หรือ Inventory
② MySQL กับ MariaDB เลือกอะไร
oxmysql รองรับ MySQL และ MariaDB
เอกสาร oxmysql ปัจจุบันแนะนำ MariaDB เพื่อ Compatibility กับ FiveM Resources จำนวนมาก เนื่องจาก Scripts รุ่นเก่าหลายตัวถูกออกแบบโดยอิงพฤติกรรมในยุค MySQL 5.7
MySQL 8 ก็ใช้งานได้ แต่ Script เก่าบางตัวอาจมีปัญหาเรื่อง
Reserved keywords
JSON/LONGTEXT defaults
SQL compatibility
ถ้าเริ่ม Server ใหม่และไม่มี Requirement พิเศษ MariaDB เป็นตัวเลือกที่เหมาะมาก
③ XAMPP จำเป็นไหม
ไม่
oxmysql Documentation ไม่แนะนำให้ติดตั้ง XAMPP เพียงเพื่อใช้ Database
XAMPP เป็น Web Development Stack ที่รวมหลาย Service เช่น
Apache
PHP
MariaDB
สำหรับ Production FiveM ควรติดตั้ง MariaDB/MySQL โดยตรงตาม Environment ที่ใช้
④ Database Server อยู่เครื่องเดียวกับ FiveM ได้ไหม
ได้
Architecture ง่ายที่สุดคือ
FXServer
+
MariaDB
อยู่เครื่องเดียวกัน
แล้วใช้ Host
127.0.0.1
หรือ
localhost
เช่น
set mysql_connection_string "mysql://fivem_user:password@127.0.0.1:3306/fivem"
ข้อดีคือไม่ต้องส่ง Database Traffic ผ่าน Internet
⑤ Database อยู่คนละเครื่องได้ไหม
ได้
เช่น
FXServer
192.168.1.10
Database
192.168.1.20
Connection String
set mysql_connection_string "mysql://fivem_user:password@192.168.1.20:3306/fivem"
แต่ Database Server ต้อง
Listen Interface ถูกต้อง
Firewall อนุญาต
Database User อนุญาต Host
Network เชื่อมถึงกัน
อย่าเปิด Port 3306 สู่ Internet โดยไม่จำเป็น
⑥ Port MySQL ปกติคืออะไร
Port มาตรฐานที่พบทั่วไปคือ
3306
ตัวอย่าง
127.0.0.1:3306
ถ้า Database Server ตั้ง Port อื่น ต้องใช้ Port จริง
เช่น
3307
Connection String ก็ต้องเปลี่ยนตาม
⑦ สร้าง Database สำหรับ FiveM
ตัวอย่าง SQL
CREATE DATABASE fivem
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
Database ชื่อ
fivem
จะเป็น Container หลักของ Tables เช่น
characters
vehicles
inventories
properties
ชื่อ Database สามารถเปลี่ยนได้ตาม Project
⑧ ทำไมใช้ utf8mb4
utf8mb4 รองรับ Unicode ได้กว้าง รวมถึง
ภาษาไทย
ภาษาอังกฤษ
อีโมจิ
อักขระพิเศษ
เหมาะกับข้อมูล FiveM เช่น
Character Name
Phone Messages
Business Names
Notes
แต่ Collation ที่เลือกควรสอดคล้องกับ Database Version และ Architecture จริง
⑨ ควรใช้ root เชื่อม FiveM ไหม
ไม่แนะนำสำหรับ Production
แม้ตัวอย่างทั่วไปจะเห็น
root
แต่ควรสร้าง Database User เฉพาะสำหรับ FiveM
เช่น
fivem_user
แล้วให้สิทธิ์เฉพาะ Database ที่ต้องใช้
⑩ สร้าง Database User
ตัวอย่าง MariaDB/MySQL
CREATE USER
'fivem_user'@'localhost'
IDENTIFIED BY
'CHANGE_THIS_PASSWORD';
จากนั้นให้ Permission
GRANT ALL PRIVILEGES
ON fivem.*
TO 'fivem_user'@'localhost';
แล้ว
FLUSH PRIVILEGES;
สำหรับ Production ควรพิจารณาหลัก Least Privilege ให้เหมาะกับสิ่งที่ Resource ต้องทำจริง
⑪ ทำไมไม่ควรใช้ root
เพราะ root มีสิทธิ์สูงมาก
หาก Credential หลุดหรือ Script มีช่องโหว่ ผลกระทบอาจเกิน Database FiveM หนึ่งชุด
ดีกว่าใช้
fivem_user
↓
เข้าถึงเฉพาะ
fivem.*
เพื่อลดขอบเขตความเสียหาย
⑫ Remote Database User ต่างจาก localhost
ถ้า FXServer กับ Database คนละเครื่อง
User
'fivem_user'@'localhost'
อาจไม่อนุญาต Remote Connection
ต้องตั้ง Host Rule ตาม Network Architecture
เช่น Database ที่รับจาก Private IP เฉพาะเครื่อง FXServer
ไม่ควรใช้
%
แบบเปิดกว้างโดยไม่เข้าใจผลด้าน Security
⑬ ทดสอบ Database ก่อน oxmysql
ก่อนโทษ oxmysql ควรยืนยันว่า Database ใช้งานได้จริง
ทดสอบ Login ด้วย Database Client เช่น
MariaDB client
MySQL client
HeidiSQL
DBeaver
โดยใช้ Credential เดียวกับที่ FiveM จะใช้
ถ้า Login จาก Database Client ยังไม่ได้ oxmysql ก็ไม่น่าจะแก้ปัญหานั้นให้
⑭ ติดตั้ง oxmysql ที่ไหน
นำ Resource oxmysql ไปไว้ใต้
resources/
เช่น
resources/
└── [standalone]/
└── oxmysql/
├── fxmanifest.lua
├── dist/
├── lib/
└── ...
ชื่อ Resource ควรเป็น
oxmysql
ตามที่ Scripts และ Dependencies อ้าง
⑮ ระวัง Folder ซ้อนหลังแตก ZIP
ผิด
resources/
└── oxmysql/
└── oxmysql/
├── fxmanifest.lua
└── ...
ควรเป็น
resources/
└── oxmysql/
├── fxmanifest.lua
└── ...
ให้ fxmanifest.lua อยู่ Root ของ Resource oxmysql
⑯ ตรวจว่า FXServer เห็น oxmysql
ถ้าเพิ่มระหว่าง Server ทำงาน
ใช้
refresh
จากนั้น
ensure oxmysql
ถ้า Console แจ้งว่าไม่พบ Resource ให้ตรวจ Folder/Manifest ก่อน Connection String
⑰ ตั้ง mysql_connection_string ตรงไหน
ตั้งใน
server.cfg
และต้องตั้ง ก่อน Start oxmysql
ตัวอย่าง
set mysql_connection_string "mysql://fivem_user:password@127.0.0.1:3306/fivem"
ensure oxmysql
อย่ากลับลำดับเป็น
ensure oxmysql
set mysql_connection_string "..."
เพราะ oxmysql ต้องอ่าน Configuration ตอนเริ่มทำงาน
⑱ Connection String แบบ URI
รูปแบบพื้นฐาน
mysql://USER:PASSWORD@HOST:PORT/DATABASE
ตัวอย่าง
set mysql_connection_string "mysql://fivem_user:MyPassword@127.0.0.1:3306/fivem"
แยกเป็น
USER
→ fivem_user
PASSWORD
→ MyPassword
HOST
→ 127.0.0.1
PORT
→ 3306
DATABASE
→ fivem
⑲ Connection String แบบ Semicolon
oxmysql รองรับอีกรูปแบบ เช่น
set mysql_connection_string "user=fivem_user;password=MyPassword;host=127.0.0.1;port=3306;database=fivem"
มีประโยชน์หาก URI Format มีปัญหากับ Character บางตัวใน Password
⑳ Password มีอักขระพิเศษต้องระวัง
เอกสาร oxmysql เตือนว่า Connection String บาง Format มี Reserved/Special Characters ที่อาจ Parse ไม่ตามที่คาด เช่นกลุ่ม
;
,
/
?
:
@
&
=
+
$
#
หาก Connection String ดูถูกต้องแต่ Parse ไม่ผ่าน ให้ตรวจ Password หรือทดลอง Connection String อีก Format
ทางที่ดีคือสร้าง Password ที่แข็งแรงแต่ไม่สร้าง Parsing Ambiguity กับ Format ที่เลือก
㉑ ไม่ควรเผย Connection String
ห้ามโพสต์
mysql://realuser:realpassword@host/database
ลง
Discord
Forum
GitHub
Screenshot
Public config
เพราะ Connection String มี Credential
หากเคยเปิดเผยแล้วควรเปลี่ยน Password ไม่ใช่แค่ลบข้อความ
㉒ set กับ setr ใช้อะไร
oxmysql Documentation ระบุให้ตั้ง Connection String ด้วย
set mysql_connection_string "..."
ใช้ set
ไม่ใช่การ Replicate Credential ไป Client
Database Credentials ต้องเป็น Server-side Configuration
㉓ server.cfg พื้นฐานควรเรียงอย่างไร
ตัวอย่าง
# Database
set mysql_connection_string "mysql://fivem_user:password@127.0.0.1:3306/fivem"
# Database connector
ensure oxmysql
# Libraries
ensure ox_lib
# Framework
ensure my_core
# Gameplay
ensure my_inventory
ensure my_garage
หลักคือ
Configuration
↓
Database Connector
↓
Core/Libraries
↓
Gameplay Resources
㉔ ตรวจ oxmysql Start สำเร็จอย่างไร
ดู FXServer Console
หาก Connection มีปัญหา oxmysql มักแสดง Error ที่เกี่ยวกับ
Authentication
Host
Database
Connection refused
Connection string
Unknown database
Access denied
อ่านข้อความแรกที่เกี่ยวข้องกับ Database
อย่า Restart ซ้ำโดยไม่อ่าน
㉕ Access denied หมายถึงอะไร
มักเกี่ยวกับ
Username ผิด
Password ผิด
Host Permission ผิด
Database User ไม่มีสิทธิ์
เช่น User ถูกสร้างเฉพาะ
localhost
แต่ Connection เกิดจาก Host อื่น
Database จะปฏิเสธ
㉖ Unknown database คืออะไร
ถ้า Error บอกว่าไม่รู้จัก Database
ตรวจ Connection String เช่น
/fivem
แล้วตรวจว่ามี Database
SHOW DATABASES;
จริงหรือไม่
อย่าสร้าง Tables ใน Database ชื่อหนึ่งแต่ Connection ไปอีกชื่อ
㉗ Connection refused คืออะไร
มักหมายถึง FXServer ติดต่อ Database Service ที่ Host/Port นั้นไม่ได้
ตรวจ
Database Service ทำงาน?
Host ถูก?
Port ถูก?
Firewall?
Bind address?
Docker/Container network?
แตกต่างจาก Access denied ซึ่งหมายถึงไปถึง Database แล้วแต่ Authentication ไม่ผ่าน
㉘ Timeout คืออะไร
ถ้า Connection Timeout
อาจเกี่ยวกับ
Network Route
Firewall
Database Host
Cloud Security Group
Port
Database Service
โดยเฉพาะ Database อยู่คนละ Server
ควรตรวจ Network ก่อนแก้ SQL Script
㉙ สร้าง Resource ทดสอบ Database
สร้าง
resources/
└── [local]/
└── db_test/
├── fxmanifest.lua
└── server.lua
เพื่อแยก Database Connection ออกจาก Framework ขนาดใหญ่
นี่เป็นวิธี Debug ที่ดีมาก
㉚ fxmanifest.lua สำหรับ db_test
fx_version 'cerulean'
game 'gta5'
author 'comsiam'
description 'oxmysql connection test'
version '1.0.0'
dependency 'oxmysql'
server_script '@oxmysql/lib/MySQL.lua'
server_script 'server.lua'
สองส่วนสำคัญคือ
dependency 'oxmysql'
และ
server_script '@oxmysql/lib/MySQL.lua'
㉛ ทำไม import MySQL.lua
@oxmysql/lib/MySQL.lua ให้ Lua Resource ใช้ Global API
MySQL
เช่น
MySQL.query.await(...)
MySQL.single.await(...)
MySQL.scalar.await(...)
ได้สะดวก
ควรประกาศก่อน Server Scripts ที่ใช้งานมัน
㉜ ทดสอบ SELECT 1
server.lua
CreateThread(function()
local result =
MySQL.scalar.await(
'SELECT 1'
)
print(
'[db_test] SELECT 1 =',
result
)
end)
ถ้า Console แสดง
[db_test] SELECT 1 = 1
Database Query พื้นฐานทำงาน
㉝ ทำไม SELECT 1 เหมาะกับการ Test
เพราะไม่ต้องพึ่ง
Table
Column
Schema ของ Framework
ถ้า
SELECT 1
ยังไม่ได้ ปัญหาน่าจะอยู่ Connection/oxmysql/Database Layer
ถ้า SELECT 1 ผ่านแต่ Query Character ไม่ผ่าน ปัญหาค่อยอยู่ Schema หรือ SQL Query
㉞ Start db_test อย่างไร
ถ้าเพิ่ม Resource ใหม่
refresh
ensure db_test
จากนั้นดู Console
อย่าทดสอบผ่าน Client Event ก่อน
ทดสอบ Server→Database ตรง ๆ ให้ผ่านก่อน
㉟ ทดสอบชื่อ Database
สามารถ Query
local database =
MySQL.scalar.await(
'SELECT DATABASE()'
)
print(
'Current database:',
database
)
ช่วยยืนยันว่า Connection กำลังใช้ Database ตัวไหนจริง
㊱ สร้าง Table สำหรับ Test
ตัวอย่าง
CREATE TABLE test_players (
id INT UNSIGNED
NOT NULL
AUTO_INCREMENT,
name VARCHAR(100)
NOT NULL,
PRIMARY KEY (id)
);
ตอนนี้มี Table สำหรับทดสอบ CRUD
㊲ ทดสอบ INSERT
local id =
MySQL.insert.await(
[[
INSERT INTO test_players (
name
)
VALUES (?)
]],
{
'Somchai'
}
)
print(
'Inserted ID:',
id
)
ถ้าได้ ID เช่น
1
แสดงว่า INSERT ใช้งานได้
㊳ ทดสอบ SELECT
local player =
MySQL.single.await(
[[
SELECT
id,
name
FROM test_players
WHERE id = ?
LIMIT 1
]],
{
1
}
)
if player then
print(
player.id,
player.name
)
end
ใช้ single เพราะต้องการเพียง Row เดียว
㊴ ทดสอบ UPDATE
local affectedRows =
MySQL.update.await(
[[
UPDATE test_players
SET name = ?
WHERE id = ?
]],
{
'Mana',
1
}
)
print(
'Updated rows:',
affectedRows
)
ถ้าได้ค่าอย่าง
1
แสดงว่ามี Row ถูก Update
㊵ ทดสอบ DELETE
ตัวอย่าง
local affectedRows =
MySQL.update.await(
[[
DELETE FROM test_players
WHERE id = ?
]],
{
1
}
)
print(
'Deleted rows:',
affectedRows
)
ใช้ Test Table เท่านั้น อย่าทดสอบ DELETE กับ Production Player Data
㊶ ทำไมต้องใช้ ?
ตัวอย่าง
WHERE id = ?
แล้ว Parameters
{
playerId
}
ทำให้ SQL Structure กับ Values แยกกัน
เป็น Pattern ที่ปลอดภัยกว่าการ Concatenate Input ลง SQL
㊷ ห้ามทำ SQL แบบนี้
ไม่ควร
local sql =
"SELECT * FROM users WHERE name = '"
.. playerName
.. "'"
โดยเฉพาะ playerName มาจาก Client
ควรเป็น
MySQL.single.await(
'SELECT * FROM users WHERE name = ? LIMIT 1',
{
playerName
}
)
㊸ Parameterized Query แทน Server Validation ไหม
ไม่
สมมติ Client ส่ง
vehicleId = 500
แม้ใช้
WHERE id = ?
อย่างปลอดภัย Server ยังต้องตรวจว่า Vehicle 500 เป็นของ Player หรือไม่
ดังนั้น
Parameterized SQL
→ ป้องกัน Database Input Layer
ส่วน
Server Validation
→ ป้องกัน Gameplay/Authorization Layer
ต้องมีทั้งคู่
㊹ Resource จริงควรประกาศ dependency
เช่น Garage
fx_version 'cerulean'
game 'gta5'
dependency 'oxmysql'
server_script '@oxmysql/lib/MySQL.lua'
server_scripts {
'server/database.lua',
'server/main.lua'
}
เปิด Manifest แล้วเห็นทันทีว่า Garage ต้องใช้ Database Connector
㊺ Start Order ของ Resource จริง
server.cfg
set mysql_connection_string "mysql://fivem_user:password@127.0.0.1:3306/fivem"
ensure oxmysql
ensure my_core
ensure my_inventory
ensure my_garage
ถ้า my_core พึ่ง oxmysql ก็ควรอยู่หลัง oxmysql
㊻ อย่าแก้ Start Order ด้วย Wait
ผิด
CreateThread(function()
Wait(5000)
MySQL.query.await(
'SELECT 1'
)
end)
เพียงเพราะ Database Resource Start ไม่ทัน
ควรแก้
Dependency
Start order
Connection
Initialization
ให้ถูกต้อง
㊼ Database Ready ควรออกแบบอย่างไร
อย่า Query ก่อน Database Layer พร้อมโดยไม่มีเหตุผล
Resource ที่มี Dependency ถูกต้องและ oxmysql Start ก่อนจะลดปัญหานี้มาก
สำหรับ Data Initialization จำนวนมาก อาจสร้าง Function
local function loadData()
local rows =
MySQL.query.await(
'SELECT * FROM garages'
)
-- Build cache
end
แล้วเรียกใน Resource Initialization ที่เหมาะสม
㊽ เปิด Slow Query Warning
สามารถตั้ง Threshold
set mysql_slow_query_warning 150
oxmysql จะเตือน Query ที่ใช้เวลานานเกิน Threshold ที่กำหนด
มีประโยชน์มากเมื่อ Server เริ่มมี Players และ Tables ใหญ่
㊾ Slow Query Warning ไม่ได้แปลว่า SQL พัง
Query Time สามารถได้รับผลจาก
Server Hitch
Database Load
Disk
Network
Startup Load
Lock
Large Result
ดังนั้น Warning คือจุดเริ่มตรวจ
ไม่ใช่คำตอบสุดท้าย
㊿ เปิด mysql_debug
ระหว่าง Development สามารถใช้
set mysql_debug true
เพื่อช่วยดู Query Activity ตามที่ oxmysql รองรับ
แต่อย่าเปิด Logging หนักโดยไม่จำเป็นตลอด Production
เพราะอาจสร้าง Log Noise จำนวนมาก
51 วิธี Debug ถ้า SELECT 1 ไม่ผ่าน
ใช้ลำดับ
① oxmysql Resource มีจริง?
② oxmysql Start ผ่าน?
③ mysql_connection_string ถูก?
④ Database Service Running?
⑤ Host ถูก?
⑥ Port ถูก?
⑦ Database Name ถูก?
⑧ Username ถูก?
⑨ Password ถูก?
⑩ User Host Permission ถูก?
⑪ Firewall เปิดหรือไม่?
⑫ Database User มี Permission หรือไม่?
อย่าไปแก้ server.lua ก่อนถ้า Connection ยังไม่ผ่าน
52 วิธี Debug ถ้า SELECT 1 ผ่าน แต่ Query จริงไม่ผ่าน
ถ้า
SELECT 1
ผ่าน แสดงว่า Connection Layer ดีในระดับพื้นฐาน
ตรวจต่อ
Table มีไหม?
Column มีไหม?
ชื่อ Database ถูกไหม?
SQL Syntax ถูกไหม?
Reserved keyword?
Parameter ถูกไหม?
Data Type ตรงไหม?
ตอนนี้ปัญหาอยู่ Schema/Query Layer มากกว่า Connection
53 Table doesn't exist แก้อย่างไร
ตรวจ
SHOW TABLES;
และตรวจว่า Script ต้องการชื่ออะไร
เช่น Script Query
SELECT *
FROM owned_vehicles
แต่ Database มี
vehicles
ก็ไม่ใช่ Table เดียวกัน
ต้อง Import Schema ที่ Resource ต้องการหรือแก้ Query ตาม Architecture
54 Unknown column แก้อย่างไร
ตัวอย่าง
Unknown column 'garage'
หมายถึง SQL กำลังอ้าง Column ที่ไม่มีใน Table ที่ Database ใช้อยู่
อาจเกิดจาก
SQL migration ยังไม่ได้ Import
Resource ใหม่กว่า Schema
Schema ใหม่กว่า Script
เลือก Database ผิด
ไม่ใช่ปัญหา Connection String แล้ว
55 Reserved Keyword มีผลไหม
มี โดยเฉพาะ Resource รุ่นเก่ากับ MySQL รุ่นใหม่
คำอย่าง
group
stored
อาจมี Compatibility Considerations ตาม Version/SQL Mode
นี่เป็นหนึ่งในเหตุผลที่ oxmysql Documentation แนะนำ MariaDB เพื่อ Compatibility กับ FiveM Resources จำนวนมาก
56 Database อยู่ Remote Server ต้องทำอะไรเพิ่ม
ตรวจ
Database bind address
Firewall
Cloud security rules
Database user host
Private networking
Latency
TLS ตาม Environment
ถ้าเป็น VPS สองเครื่องใน Private Network ควรใช้ Private IP เมื่อเหมาะสม แทนเปิด Database สู่ Public Internet
57 Database User ต้องมี Permission อะไร
ขึ้นกับ Resource
Gameplay Resource ทั่วไปอาจต้อง
SELECT
INSERT
UPDATE
DELETE
Framework Installer หรือ Migration อาจต้องเพิ่ม
CREATE
ALTER
INDEX
ถ้าต้องสร้าง/เปลี่ยน Schema
หลักคือให้สิทธิ์เท่าที่ระบบต้องใช้จริง
58 Backup ก่อน Import SQL
ก่อน Import Script SQL ลง Production Database ควร Backup
เพราะไฟล์ SQL อาจมี
DROP TABLE
ALTER TABLE
DELETE
TRUNCATE
อย่า Import โดยไม่อ่าน
โดยเฉพาะ SQL จาก Resource ที่ไม่รู้ที่มา
59 Checklist เชื่อม FiveM กับ MySQL/MariaDB
ตรวจให้ครบ
① MariaDB/MySQL ติดตั้งแล้ว?
② Database Service Running?
③ สร้าง Database แล้ว?
④ Character Set เหมาะสม?
⑤ สร้าง Dedicated User แล้ว?
⑥ Password ปลอดภัย?
⑦ User มี Permission?
⑧ Host Permission ถูก?
⑨ oxmysql อยู่ใน resources?
⑩ Folder oxmysql ไม่ซ้อน?
⑪ FXServer เห็น oxmysql?
⑫ mysql_connection_string ถูก?
⑬ ใช้ set ไม่ใช่ Replicated Credential?
⑭ Connection String อยู่ก่อน oxmysql?
⑮ Host ถูก?
⑯ Port ถูก?
⑰ Database Name ถูก?
⑱ Special Character ทำให้ Parse มีปัญหาหรือไม่?
⑲ oxmysql Start ผ่าน?
⑳ Consumer Start หลัง oxmysql?
㉑ Resource มี dependency 'oxmysql'?
㉒ MySQL.lua ถูก Import ก่อน Server Scripts?
㉓ SELECT 1 ผ่าน?
㉔ SELECT DATABASE() ถูก Database?
㉕ INSERT ผ่าน?
㉖ SELECT ผ่าน?
㉗ UPDATE ผ่าน?
㉘ Queries ใช้ Parameters?
㉙ Client Input ถูก Validate?
㉚ Backup Database แล้ว?
⑥⓪ ตัวอย่าง Setup FiveM + MariaDB + oxmysql แบบครบ
สมมติ Database คือ
com_fivem
และ Database User
com_server
สร้าง Database
CREATE DATABASE com_fivem
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
สร้าง User
CREATE USER
'com_server'@'localhost'
IDENTIFIED BY
'CHANGE_THIS_PASSWORD';
ให้ Permission
GRANT ALL PRIVILEGES
ON com_fivem.*
TO 'com_server'@'localhost';
FLUSH PRIVILEGES;
server.cfg
set mysql_connection_string "mysql://com_server:CHANGE_THIS_PASSWORD@127.0.0.1:3306/com_fivem"
set mysql_slow_query_warning 150
ensure oxmysql
ensure com_database_test
Resource Structure
com_database_test/
├── fxmanifest.lua
└── server/
└── main.lua
fxmanifest.lua
fx_version 'cerulean'
game 'gta5'
author 'comsiam'
description 'FiveM database connection test'
version '1.0.0'
dependency 'oxmysql'
server_script '@oxmysql/lib/MySQL.lua'
server_script 'server/main.lua'
server/main.lua
CreateThread(function()
local test =
MySQL.scalar.await(
'SELECT 1'
)
if test ~= 1 then
print(
'[DB TEST] Database test failed'
)
return
end
local database =
MySQL.scalar.await(
'SELECT DATABASE()'
)
print(
'[DB TEST] Connection OK'
)
print(
'[DB TEST] Database:',
database
)
end)
เมื่อ Start
refresh
ensure com_database_test
ถ้าทุกอย่างถูกต้องควรได้ Concept
oxmysql
↓
Connected
↓
SELECT 1
↓
1
↓
SELECT DATABASE()
↓
com_fivem
ตอนนี้จึงค่อยเริ่มสร้าง Tables และ Resource จริง
ตัวอย่าง Resource Garage เชื่อม Database
fxmanifest.lua
fx_version 'cerulean'
game 'gta5'
dependency 'oxmysql'
server_script '@oxmysql/lib/MySQL.lua'
server_scripts {
'server/database.lua',
'server/main.lua'
}
server/database.lua
Database = {}
function Database.getVehicles(
characterId
)
return MySQL.query.await(
[[
SELECT
id,
plate,
model,
stored
FROM vehicles
WHERE character_id = ?
]],
{
characterId
}
)
end
server/main.lua
RegisterNetEvent(
'garage:getVehicles',
function()
local src =
source
local characterId =
GetCharacterId(src)
if not characterId then
return
end
local vehicles =
Database.getVehicles(
characterId
)
TriggerClientEvent(
'garage:vehicles',
src,
vehicles
)
end
)
Architecture คือ
Client
↓
garage:getVehicles
↓
Server
↓
หา Character ID
↓
Database.getVehicles
↓
oxmysql
↓
MariaDB
↓
Rows
↓
Server
↓
Client
Client ไม่ได้เข้าถึง Database โดยตรง
อย่าเปิด Generic SQL Event ให้ Client
ห้ามออกแบบ
RegisterNetEvent(
'database:query',
function(sql)
MySQL.query.await(
sql
)
end
)
เพราะเท่ากับให้ Client ส่ง SQL มายัง Database Server
ควรออกแบบ Event เป็น Business Action
เช่น
garage:getVehicles
shop:buyItem
character:create
และให้ Server เป็นผู้กำหนด SQL
อย่าเก็บ Connection String ใน Shared Script
ไม่ควร
Config.Database =
'mysql://user:password@host/database'
ใน
shared/config.lua
เพราะ Shared Script ถูก Client โหลด
Connection String ต้องอยู่ Server Configuration
mysql_connection_string ต้องมาก่อน oxmysql
จำลำดับนี้ให้แม่น
server.cfg
↓
mysql_connection_string
↓
oxmysql
↓
Core
↓
Gameplay Resources
ไม่ใช่
Gameplay Resource
↓
oxmysql
↓
Connection String
เพราะ Database Layer ต้องพร้อมก่อน Consumer เรียกใช้งาน
คำถามที่พบบ่อยเกี่ยวกับการเชื่อม FiveM กับ MySQL/MariaDB
FiveM เชื่อม MySQL อย่างไร
ใช้ Database Connector เช่น oxmysql ระหว่าง Server Scripts กับ MySQL/MariaDB
oxmysql เป็น Database ไหม
ไม่ เป็น Connector
ต้องติดตั้ง MariaDB ด้วยไหม
ต้องมี MySQL-compatible Database Server ที่ oxmysql เชื่อมได้
MariaDB หรือ MySQL ดีกว่าสำหรับ FiveM
oxmysql Documentation แนะนำ MariaDB สำหรับ Compatibility กับ FiveM Resources จำนวนมาก ขณะที่ MySQL 8 ก็รองรับ
ต้องใช้ XAMPP ไหม
ไม่ oxmysql Documentation ไม่แนะนำ XAMPP เพียงเพื่อทำ Database Server
mysql_connection_string อยู่ตรงไหน
โดยทั่วไปอยู่ใน server.cfg
Connection String ต้องอยู่ก่อน oxmysql ไหม
ใช่ ควรกำหนดก่อน Start Resource ที่ใช้ Database
รูปแบบ Connection String เป็นอย่างไร
ตัวอย่าง
set mysql_connection_string "mysql://user:password@127.0.0.1:3306/fivem"
ใช้ Semicolon Format ได้ไหม
ได้ เช่น
set mysql_connection_string "user=user;password=password;host=127.0.0.1;port=3306;database=fivem"
Password มี @ แล้วต่อไม่ได้ทำอย่างไร
อักขระบางชนิดมีความหมายพิเศษใน Connection String Format ให้เปลี่ยน Format หรือใช้ Password ที่ไม่สร้าง Parsing Conflict ตามแนวทาง Documentation
oxmysql ต้อง ensure ก่อน Framework ไหม
ถ้า Framework ใช้ Database ควรให้ oxmysql พร้อมก่อน
fxmanifest.lua ต้องเขียนอะไร
ตัวอย่าง
dependency 'oxmysql'
server_script '@oxmysql/lib/MySQL.lua'
ทดสอบ Connection อย่างไร
ใช้
SELECT 1
ผ่าน MySQL.scalar.await
SELECT 1 ได้ 1 หมายความว่าอะไร
แสดงว่า Server Resource สามารถส่ง Database Query ผ่าน oxmysql ได้ในระดับพื้นฐาน
ตรวจชื่อ Database ที่เชื่อมอยู่ได้ไหม
ได้ด้วย
SELECT DATABASE()
Access denied แก้อย่างไร
ตรวจ Username, Password, Host Permission และ Database Privileges
Unknown database แก้อย่างไร
ตรวจว่าชื่อ Database ใน Connection String มีอยู่จริง
Connection refused แก้อย่างไร
ตรวจ Database Service, Host, Port, Firewall และ Network
Table doesn't exist เป็นปัญหา oxmysql ไหม
ไม่จำเป็น Connection อาจทำงานแล้วแต่ Database Schema ไม่มี Table ที่ Script ต้องการ
Unknown column คืออะไร
SQL กำลังเรียก Column ที่ไม่มีหรือ Schema Version ไม่ตรงกับ Resource
Database Remote ต้องเปิด 3306 สาธารณะไหม
ไม่ควรหากหลีกเลี่ยงได้ ควรใช้ Private Network/Firewall Rules ที่จำกัดแหล่งเชื่อมต่อ
ใช้ root เชื่อม Database ได้ไหม
ทำได้ทางเทคนิคในหลายระบบ แต่ไม่แนะนำสำหรับ Production ควรสร้าง Dedicated User
Database Password ใส่ใน client.lua ได้ไหม
ไม่ได้และไม่ควรอย่างยิ่ง
Resource ต้องใช้ Placeholder ไหม
ควรใช้ Parameterized Queries แทนการ Concatenate Untrusted Values ลง SQL
oxmysql ป้องกัน Cheat ไหม
ไม่ Server-side Validation ยังจำเป็น
Slow Query Warning เปิดอย่างไร
ตัวอย่าง
set mysql_slow_query_warning 150
mysql_debug เปิดอย่างไร
ตัวอย่าง
set mysql_debug true
ใช้เมื่อ Debug ตามความจำเป็น
สรุปวิธีเชื่อม FiveM กับ MySQL หรือ MariaDB ด้วย oxmysql
ขั้นตอนทั้งหมดสามารถสรุปเป็น
① ติดตั้ง MariaDB/MySQL
↓
② สร้าง Database
↓
③ สร้าง Database User
↓
④ กำหนด Permission
↓
⑤ ติดตั้ง oxmysql
↓
⑥ ตั้ง mysql_connection_string
↓
⑦ Start oxmysql
↓
⑧ Import MySQL.lua ใน Resource
↓
⑨ ประกาศ dependency
↓
⑩ ทดสอบ SELECT 1
↓
⑪ ทดสอบ SELECT DATABASE()
↓
⑫ ค่อยสร้างระบบจริง
ตัวอย่าง Configuration ขั้นต่ำ
set mysql_connection_string "mysql://fivem_user:password@127.0.0.1:3306/fivem"
ensure oxmysql
ensure my_resource
Manifest
fx_version 'cerulean'
game 'gta5'
dependency 'oxmysql'
server_script '@oxmysql/lib/MySQL.lua'
server_script 'server.lua'
และ Test
local result =
MySQL.scalar.await(
'SELECT 1'
)
print(result)
ถ้าได้
1
จึงค่อยพัฒนา Query จริง เช่น
Characters
Vehicles
Inventory
Money
Properties
สิ่งสำคัญที่สุดคืออย่า Debug ทุก Layer พร้อมกัน
ถ้า Connection ยังไม่ผ่าน ให้แก้
Database
Credential
Host
Port
Connection String
oxmysql
ก่อน
ถ้า SELECT 1 ผ่านแล้วแต่ vehicles Query พัง ค่อยแก้
Schema
Table
Column
SQL
Parameters
สำหรับ Developer ที่เรียน FiveM กับ comsiam วิธีนี้จะช่วยลดเวลา Debug ได้มาก เพราะเรารู้แน่นอนว่าปัญหาอยู่ Connection Layer หรือ Application Layer
อีกหลักสำคัญจาก comsiam คือ Database ต้องอยู่หลัง Server Authority เสมอ:
Client Request
↓
Server Validate
↓
Server Query
↓
Database
ไม่ใช่ให้ Client เลือก SQL, Table หรือค่าที่มีผลต่อ Economy แล้วส่งให้ Database บันทึกตรง ๆ
หัวข้อถัดไปคือ FiveM Database Connection Failed แก้อย่างไร ซึ่งจะเจาะ Error จริง เช่น Access denied, ECONNREFUSED, Unknown database, Timeout, Password มีอักขระพิเศษ, Host Permission, Port 3306 และวิธีแยกว่า Error อยู่ที่ FXServer, oxmysql, Network หรือ MariaDB
Comments
Post a Comment