oxmysql คืออะไร ทำไม FiveM ต้องใช้
oxmysql คือ Database Resource สำหรับ FXServer/FiveM ที่ทำหน้าที่เป็นตัวกลางระหว่าง Server Scripts กับฐานข้อมูล MySQL/MariaDB
พูดง่าย ๆ คือ เมื่อ FiveM Server ต้องการบันทึกข้อมูลอย่าง
ตัวละคร
เงิน
อาชีพ
รถ
บ้าน
Inventory
โทรศัพท์
ธุรกิจ
Gang
บัญชีธนาคาร
Script ฝั่ง Server จะส่งคำสั่ง SQL ผ่าน oxmysql ไปยัง Database
โครงสร้างพื้นฐานคือ
FiveM Script
↓
oxmysql
↓
MariaDB / MySQL
↓
Database Tables
ดังนั้น oxmysql ไม่ใช่ฐานข้อมูล แต่เป็น ตัวเชื่อม FiveM กับฐานข้อมูล
① oxmysql คืออะไรแบบง่ายที่สุด
สมมติ Player มีเงินในธนาคาร
Bank = $50,000
เมื่อ Player ฝากเพิ่ม
$10,000
Server ต้องเปลี่ยนข้อมูลเป็น
Bank = $60,000
และต้องจำค่าไว้แม้ Player
ออกเกม
เข้าใหม่
Restart Server
Script จึงต้องบันทึกข้อมูลลง Database
เช่น
UPDATE users
SET bank = ?
WHERE identifier = ?
oxmysql ทำหน้าที่ส่ง Query นี้จาก FXServer ไปยัง Database
② oxmysql ไม่ใช่ Database
นี่เป็นจุดที่มือใหม่มักสับสน
oxmysql
≠ Database Server
และ
oxmysql
≠ MariaDB
โครงสร้างจริงคือ
FiveM
↓
oxmysql
↓
MariaDB
ดังนั้นแม้ติดตั้ง oxmysql แล้ว ถ้าไม่มี Database Server ระบบก็ยังเก็บข้อมูลไม่ได้
③ MariaDB คืออะไร
MariaDB คือ Database Server ที่เก็บข้อมูลจริง
ตัวอย่าง Tables
users
players
vehicles
owned_vehicles
ox_inventory
phone_messages
bank_accounts
ภายใน Tables จะมี Rows ของ Players และข้อมูลต่าง ๆ
oxmysql เป็นเพียง Layer ที่ใช้ส่งคำสั่งไปยัง MariaDB
④ MySQL ใช้ได้หรือไม่
ใช้ได้ แต่ Documentation ปัจจุบันของ oxmysql แนะนำ MariaDB
เหตุผลหนึ่งคือ FiveM Resources จำนวนมากถูกพัฒนามาจาก Ecosystem ที่เดิมใช้ MySQL 5.7 และอาจพบ Compatibility Differences เมื่อใช้ MySQL 8
เช่น
Reserved keywords เพิ่มขึ้น
JSON/LONGTEXT behavior บางส่วนต่างกัน
ดังนั้นสำหรับ FiveM Server ใหม่ การใช้ MariaDB ตาม Current Documentation เป็นตัวเลือกที่เหมาะกว่า
⑤ XAMPP ควรใช้ไหม
Current oxmysql Documentation ระบุชัดว่า ไม่แนะนำให้ติดตั้ง XAMPP เพียงเพื่อใช้ Database กับ FiveM
XAMPP เป็น Development Web Server Stack ที่รวมหลายระบบ เช่น
Apache
PHP
MariaDB/MySQL
แต่ FiveM Server ต้องการ Database Server เป็นหลัก
สำหรับ Production จึงควรติดตั้ง
MariaDB
โดยตรง
⑥ FiveM จำเป็นต้องใช้ oxmysql ทุก Server หรือไม่
ไม่จำเป็น
ถ้าเป็น Server ง่าย ๆ เช่น
Drift
Freeroam
Deathmatch
Temporary Game Mode
ที่ไม่ต้องเก็บข้อมูล Persistent อาจไม่ต้องมี Database เลย
แต่ RP Server ส่วนใหญ่มักต้องเก็บ
Characters
Money
Jobs
Vehicles
Inventory
Housing
Phone
Businesses
จึงแทบหลีกเลี่ยง Database ไม่ได้
และหาก Framework/Resources ใช้ oxmysql ก็ต้องติดตั้งมัน
⑦ ทำไม FiveM RP ต้องมี Database
ลองคิดว่าไม่มี Database
Player เข้า Server
สร้างตัวละคร
หาเงิน
ซื้อรถ
ซื้อบ้าน
เก็บ Item
จากนั้นออกเกม
ถ้าทุกอย่างอยู่ใน Memory อย่างเดียว เมื่อ Server Restart ข้อมูลอาจหายทั้งหมด
Database ทำให้ข้อมูลเป็น
Persistent Data
คือสามารถอยู่ต่อหลัง Session จบ
⑧ oxmysql ทำหน้าที่ตรงไหน
Architecture ของ RP Server อาจเป็น
Player
↓
FiveM Client
↓
Server Script
↓
Framework
↓
oxmysql
↓
MariaDB
ตัวอย่าง
Player ซื้อรถ
↓
Dealership Script
↓
ตรวจเงิน
↓
หักเงิน
↓
สร้าง Vehicle Record
↓
oxmysql
↓
Database
เมื่อ Player เข้าใหม่ รถจึงยังอยู่
⑨ Framework ไหนใช้ oxmysql
Framework ปัจจุบันหลายตัวใช้ oxmysql
เช่น
ESX Legacy
QBCore
Qbox
ox_core
รวมถึง Resources จำนวนมากใน OX ecosystem
ดังนั้น oxmysql ไม่ได้จำกัดอยู่กับ Framework ใด Framework หนึ่ง
⑩ ESX ใช้ oxmysql หรือไม่
Current ESX Legacy Core ใช้
@oxmysql/lib/MySQL.lua
ใน Server Scripts และประกาศ oxmysql เป็น Dependency
ดังนั้น Server ESX รุ่นปัจจุบันจำนวนมากใช้ Stack
MariaDB
↓
oxmysql
↓
es_extended
ไม่ควรยึด Tutorial ESX เก่าที่ใช้ mysql-async เป็นมาตรฐานปัจจุบันโดยไม่ตรวจ Version
⑪ QBCore ใช้ oxmysql หรือไม่
Current qb-core ก็ใช้
@oxmysql/lib/MySQL.lua
และมี oxmysql เป็น Dependency
Architecture โดยทั่วไปคือ
MariaDB
↓
oxmysql
↓
qb-core
จากนั้น Resources ใน QBCore Ecosystem จึงเข้าถึงข้อมูลผ่าน Framework หรือ Database APIs ตาม Design
⑫ Qbox ใช้ oxmysql หรือไม่
ใช้
Qbox/OX-first Stack โดยทั่วไปจะเห็น
MariaDB
↓
oxmysql
↓
ox_lib
↓
qbx_core
↓
ox_inventory
ดังนั้น Database Layer เป็นส่วนพื้นฐานของ Qbox Server
⑬ ox_core ใช้ oxmysql หรือไม่
ใช้เช่นกัน
ox_core ต้องเก็บข้อมูลอย่าง
Users
Characters
Groups
Accounts
Vehicles
จึงต้องมี Persistent Database Layer
โดยมี oxmysql เป็นตัวกลางระหว่าง Framework กับ MariaDB
⑭ oxmysql ใช้เทคโนโลยีอะไร
Current Project อธิบายว่า oxmysql เป็น
FiveM resource to communicate with a MySQL database
using node-mysql2
กล่าวคือ Core Database Communication ใช้ mysql2 ใน Node.js ecosystem
Current Package Version ที่ตรวจสอบในปี 2026 คือ
oxmysql 2.14.1
โดย Release v2.14.1 ออกวันที่ 4 พฤษภาคม 2026
Version สามารถเปลี่ยนในอนาคต จึงควรตรวจ Current Release ตอนติดตั้งจริง
⑮ Script Lua เรียก oxmysql อย่างไร
วิธีที่ Documentation แนะนำคือเพิ่มใน fxmanifest.lua
server_script '@oxmysql/lib/MySQL.lua'
และต้องวางบรรทัดนี้ก่อน Server Scripts ที่เรียก MySQL
ตัวอย่าง
fx_version 'cerulean'
game 'gta5'
server_script '@oxmysql/lib/MySQL.lua'
server_script 'server.lua'
dependency 'oxmysql'
จากนั้นใน server.lua สามารถเรียก
MySQL.query.await(...)
ได้
⑯ ทำไมต้อง Import MySQL.lua
ไฟล์
@oxmysql/lib/MySQL.lua
สร้าง Interface
MySQL
ให้ Lua Resource
จากนั้นสามารถใช้ Methods เช่น
MySQL.query
MySQL.single
MySQL.scalar
MySQL.insert
MySQL.update
MySQL.prepare
MySQL.transaction
แทนการเรียก Raw Exports ทุกครั้ง
⑰ MySQL.query คืออะไร
ใช้ Execute Query และคืนข้อมูลที่ตรงกับ Query
ตัวอย่าง
local players = MySQL.query.await(
'SELECT `identifier`, `name` FROM `users`'
)
ถ้ามีหลาย Rows จะได้ข้อมูลกลับมาเป็น Table
เหมาะกับ
SELECT หลาย Records
ค้นรายการรถ
โหลดรายการธุรกิจ
โหลด Characters
⑱ ตัวอย่าง Query แบบมี WHERE
local result = MySQL.query.await(
'SELECT * FROM `users` WHERE `identifier` = ?',
{ identifier }
)
ค่า
?
คือ Placeholder
ค่าจริงส่งแยกใน Parameters
{ identifier }
วิธีนี้ดีกว่าการต่อ String จาก Input โดยตรง
⑲ ทำไมควรใช้ Parameters
ไม่ควรเขียนแบบนี้
local query = "SELECT * FROM users WHERE identifier = '" .. identifier .. "'"
โดยเฉพาะถ้าข้อมูลส่วนใดมาจาก User Input
ควรใช้
MySQL.query.await(
'SELECT * FROM users WHERE identifier = ?',
{ identifier }
)
Parameterized Queries ช่วยจัดการ Parameters อย่างถูกต้องและลดความเสี่ยง SQL Injection เมื่อใช้งานอย่างเหมาะสม
⑳ SQL Injection คืออะไร
สมมติ Script นำข้อความจาก User ไปต่อ SQL ตรง ๆ
User Input
↓
SQL String
↓
Database
ผู้ไม่หวังดีอาจพยายามใส่ SQL Syntax เพิ่มเข้าไป
จึงควรใช้
Placeholders
+
Parameters
แทนการต่อ User Input เข้า Query โดยตรง
แต่ Security ยังต้องรวมถึง
Validation
Authorization
Permissions
Data Type Checking
ด้วย
㉑ MySQL.single คืออะไร
ใช้เมื่อต้องการ Row เดียว
ตัวอย่าง
local player = MySQL.single.await(
'SELECT `firstname`, `lastname` FROM `users` WHERE `identifier` = ? LIMIT 1',
{ identifier }
)
if not player then
return
end
print(player.firstname, player.lastname)
ต่างจาก query ที่คืนรายการ Rows
single เหมาะเมื่อเราคาดหวัง Record เดียว
㉒ query กับ single ต่างกันอย่างไร
query
อาจคืนหลาย Rows
Row 1
Row 2
Row 3
single
คืน
Row เดียว
ดังนั้นถ้าค้น Player จาก Unique Identifier
single
มักอ่าน Code ง่ายกว่า Query แล้วใช้ [1]
㉓ MySQL.scalar คืออะไร
scalar คืนค่าของ Column แรกจาก Row แรก
ตัวอย่างต้องการ Bank Balance อย่างเดียว
local balance = MySQL.scalar.await(
'SELECT `bank` FROM `users` WHERE `identifier` = ?',
{ identifier }
)
ผลอาจเป็น
50000
แทน Table ทั้ง Row
㉔ scalar เหมาะกับอะไร
เหมาะกับ Query เช่น
COUNT(*)
SUM(...)
ชื่อเดียว
ยอดเงินเดียว
Status เดียว
ตัวอย่าง
local count = MySQL.scalar.await(
'SELECT COUNT(*) FROM `vehicles` WHERE `owner` = ?',
{ identifier }
)
ไม่จำเป็นต้อง Query Row เต็มหากต้องการค่าเดียว
㉕ MySQL.insert คืออะไร
ใช้เพิ่ม Row แล้วคืน
Insert ID
ถ้ามี Auto Increment ID
ตัวอย่าง
local id = MySQL.insert.await(
'INSERT INTO `characters` (`identifier`, `firstname`) VALUES (?, ?)',
{
identifier,
firstName
}
)
print(id)
เหมาะกับการสร้าง Record ใหม่
㉖ MySQL.update คืออะไร
ใช้สำหรับ Query ที่ต้องการรู้จำนวน Rows ที่ได้รับผลกระทบ
ตัวอย่าง
local affectedRows = MySQL.update.await(
'UPDATE `users` SET `bank` = ? WHERE `identifier` = ?',
{
balance,
identifier
}
)
ผลลัพธ์อาจเป็น
0
1
2
...
ตามจำนวน Rows ที่ถูกแก้
㉗ update ใช้กับ DELETE ได้หรือไม่
แนวคิดของ Method นี้เหมาะกับ Statements ที่ต้องการ
affectedRows
เช่น
UPDATE
DELETE
ตาม Query ที่ใช้
สิ่งสำคัญคือเลือก Method ตาม ผลลัพธ์ที่ต้องการ ไม่ใช่เลือก query กับทุกคำสั่งโดยอัตโนมัติ
㉘ MySQL.prepare คืออะไร
prepare ใช้ Prepared Statement Execution
ตัวอย่าง
local result = MySQL.prepare.await(
'SELECT `username` FROM `users` WHERE `id` = ?',
{ userId }
)
และสามารถทำ Query เดียวกับ Parameter Sets หลายชุดตาม API
เหมาะกับ Query ที่ถูกเรียกซ้ำและต้องการรูปแบบ Parameters ที่ชัดเจน
㉙ prepare ดีกว่า query เสมอไหม
ไม่ควรสรุปแบบนั้น
ต้องเลือกตาม Use Case
query
→ General Query
single
→ Row เดียว
scalar
→ ค่าเดียว
insert
→ Insert ID
update
→ Affected Rows
prepare
→ Prepared execution
transaction
→ หลาย Query ที่ต้องสำเร็จร่วมกัน
การเลือก Function ที่ตรงกับข้อมูลที่ต้องการทำให้ Code อ่านง่ายกว่า
㉚ MySQL.transaction คืออะไร
Transaction ใช้เมื่อหลาย SQL Statements ต้องถือเป็น งานชุดเดียวกัน
หลักคือ
ทุก Query สำเร็จ
→ COMMIT
มี Query ใด Query หนึ่งล้มเหลว
→ ไม่ Commit ทั้งชุด
Current Documentation ระบุชัดว่า หาก Query หนึ่ง Fail จะไม่มี Query ใน Transaction นั้นถูก Commit
㉛ Transaction สำคัญกับระบบเงินอย่างไร
สมมติโอนเงิน
Player A
↓ -10,000
Player B
↑ +10,000
ถ้าทำเป็นสอง Query แยกกัน
หัก Player A สำเร็จ
↓
Server/Query B Error
↓
Player B ไม่ได้เงิน
เงินหายจาก Economy
Transaction ช่วยให้
หัก A
+
เพิ่ม B
เป็นงานชุดเดียว
ถ้าขั้นตอนใดล้มเหลวทั้งหมดสามารถไม่ Commit
㉜ ตัวอย่าง Transaction
local queries = {
{
'UPDATE accounts SET balance = balance - ? WHERE id = ?',
{ amount, fromAccount }
},
{
'UPDATE accounts SET balance = balance + ? WHERE id = ?',
{ amount, toAccount }
}
}
local success = MySQL.transaction.await(queries)
if not success then
print('Transaction failed')
end
นี่เหมาะกับ Banking/Economy Logic
แต่ Server ต้องตรวจว่า Sender มีเงินเพียงพอก่อนและออกแบบ Query ให้ป้องกัน Race Conditions ตามระบบด้วย
㉝ Transaction ใช้กับอะไรอีก
เหมาะกับ
ซื้อรถ
ซื้อบ้าน
ซื้อธุรกิจ
Trade
Bank Transfer
Marketplace
Crafting ที่เกี่ยวหลาย Tables
Character Creation หลาย Tables
โดยเฉพาะ Action ที่ข้อมูลหลายจุดต้องสอดคล้องกันทั้งหมด
㉞ Transaction Isolation Level ปรับได้ไหม
ได้
Current Documentation มี Convar
mysql_transaction_isolation_level
ค่าอยู่ระหว่าง
1–4
และ Current Default ระบุเป็น
2 = Read Committed
การเปลี่ยน Isolation Level ควรทำเฉพาะเมื่อเข้าใจ Database Transactions จริง เพราะมีผลต่อ Concurrency และ Locking
㉟ Callback กับ await ต่างกันอย่างไร
oxmysql รองรับทั้งสองรูปแบบ
Callback
MySQL.query(
'SELECT * FROM users',
{},
function(result)
print(#result)
end
)
await
local result = MySQL.query.await(
'SELECT * FROM users'
)
print(#result)
await มักทำให้ Flow ของ Lua Code อ่านง่ายขึ้น
㊱ await ทำให้ Server ทั้งเครื่องหยุดหรือไม่
ไม่ควรเข้าใจคำว่า await ว่าเป็นการ Freeze FXServer ทั้งหมด
oxmysql รองรับ Promise/Async Query Handling และ Lua Coroutine-style awaiting
ดังนั้น Code สามารถรอผล Query ใน Execution Context นั้นได้โดยไม่หมายความว่า Database Query เดียวหยุดทุก Resource ทั้ง Server
อย่างไรก็ตาม Query ที่ช้าและ Query จำนวนมากยังสร้างภาระให้ Database/Server ได้จริง
㊲ Async ไม่ได้แปลว่า Query ช้าไม่มีผล
ถึงระบบจะจัดการ Query แบบ Async ได้
ถ้ามี Script ทำ
10,000 Queries
ทุกไม่กี่วินาที
Database ก็ยังทำงานหนัก
Performance ต้องพิจารณา
จำนวน Queries
Indexes
Query Design
Rows ที่อ่าน
Connection Pool
Database Hardware
ไม่ใช่เพียงเลือก await หรือ Callback
㊳ SELECT * ควรใช้ทุกครั้งไหม
ไม่ควร
ถ้าต้องการเพียง
firstname
lastname
ควร Query
SELECT firstname, lastname
FROM users
WHERE identifier = ?
แทน
SELECT *
FROM users
โดยเฉพาะ Tables ใหญ่
ช่วยลดข้อมูลที่ Database ต้องส่งกลับ
㊴ LIMIT 1 มีประโยชน์เมื่อไร
ถ้าค้น Record เดียว เช่น
identifier
citizenid
vehicle id
สามารถใช้
LIMIT 1
เมื่อ Logic และ Schema เหมาะสม
ตัวอย่าง
MySQL.single.await(
'SELECT `firstname` FROM `users` WHERE `identifier` = ? LIMIT 1',
{ identifier }
)
ช่วยสื่อ Intent ว่าต้องการเพียง Record เดียว
㊵ Database Index สำคัญกว่าเปลี่ยน Library บางครั้ง
ถ้า Query
SELECT *
FROM vehicles
WHERE owner = ?
ถูกเรียกบ่อยมาก แต่ Column owner ไม่มี Index ที่เหมาะสม
Database อาจต้อง Scan Rows จำนวนมาก
ดังนั้น Performance Problem อาจไม่ได้เกิดจาก oxmysql
แต่อยู่ที่
SQL Query
Schema
Indexes
Data Volume
ต้องใช้ Database Profiling/Slow Query Analysis ประกอบ
㊶ oxmysql มี Debug Mode หรือไม่
มี
Current Documentation รองรับ
set mysql_debug true
เพื่อ Debug Queries
และสามารถจำกัด Resource ที่ต้องการ Debug ได้
ตัวอย่างแนวคิด
set mysql_debug [
"ox_core",
"ox_inventory"
]
เหมาะกับการหา Script ที่ส่ง Query ผิดหรือช้า
㊷ เปิด mysql_debug ตลอด Production ดีไหม
ไม่จำเป็น
Debug Logging จำนวนมากสามารถสร้าง Log ปริมาณสูง
ควรเปิดเมื่อ
วิเคราะห์ Query
หา Error
หา Resource ที่ Query ผิด
แล้วปิดหรือจำกัด Scope เมื่อแก้ปัญหาแล้ว
Production Logging ควรสมดุลระหว่าง Visibility กับ Noise
㊸ Connection String คืออะไร
oxmysql ต้องรู้ว่าจะเชื่อม Database ไหน
ใช้ Convar
mysql_connection_string
ตัวอย่างรูปแบบ URI
set mysql_connection_string "mysql://fivem:StrongPassword@127.0.0.1/fivem"
ประกอบด้วย
Protocol
Username
Password
Host
Database
Port สามารถระบุเพิ่มได้ถ้าไม่ใช้ Default
㊹ Connection String ต้องอยู่ก่อน ensure oxmysql
ควรตั้ง
set mysql_connection_string "..."
ก่อน
ensure oxmysql
เพราะ oxmysql ต้องอ่าน Connection Configuration ตอนเริ่มเชื่อม Database
ตัวอย่าง
set mysql_connection_string "mysql://fivem:password@127.0.0.1/fivem"
ensure oxmysql
㊺ อย่าเปิดเผย Database Password
ไม่ควรโพสต์ Connection String จริงลง
Discord
Forum
GitHub Public Repository
Screenshot สาธารณะ
เพราะภายในมี
Username
Password
Hostname
Database
ถ้า Credential หลุดควรเปลี่ยน Password ทันที
㊻ ควรใช้ root หรือไม่
Production Server ควรสร้าง Database User เฉพาะสำหรับ FiveM
เช่น
Database:
fivem
User:
fivem_server
แทนการให้ FXServer ใช้ Database Administrator Account โดยไม่จำเป็น
หลักคือให้สิทธิ์เท่าที่ระบบต้องใช้
㊼ Connection refused คืออะไร
ถ้าเจอ
Connection refused
ให้ตรวจ
MariaDB เปิดอยู่ไหม
Host ถูกไหม
Port ถูกไหม
Firewall
Bind Address
Network
Error นี้ไม่ได้หมายความว่า SQL ของ Script ผิด
Connection ยังไปไม่ถึงขั้น Query
㊽ Access denied คืออะไร
ตัวอย่าง
Access denied for user
มักเกี่ยวกับ
Username
Password
Host permissions
Database privileges
ตรวจ Database Account ก่อน
อย่าแก้ oxmysql Source เพื่อแก้ Authentication Error
㊾ Unknown database คืออะไร
ถ้า Connection String ระบุ
fivem
แต่ Database จริงไม่มี
อาจเห็น
Unknown database
ให้สร้าง Database หรือแก้ชื่อใน Connection String
ไม่เกี่ยวกับ Player Cache
㊿ Unknown table คืออะไร
ถ้า Query ขอ
users
แต่ Table ไม่มี
Database จะ Error
สาเหตุอาจเป็น
ยังไม่ได้ Import Framework SQL
ใช้ Database ผิดตัว
Framework Bridge ผิด
Schema Version ไม่ตรง
ต้องตรวจ SQL Installation ของ Framework/Resource นั้น
51. Unknown column คืออะไร
เช่น
Unknown column 'citizenid'
อาจเกิดจาก
Schema เก่า
Framework ผิด
Migration ไม่ครบ
Query ใช้ Column คนละระบบ
เช่น Qbox/QBCore และ ESX มี Database Schemas ต่างกัน
อย่าเพิ่ม Column แบบเดาโดยไม่ตรวจ Current Schema
52. oxmysql ใช้แทน mysql-async ได้ไหม
Current Documentation ระบุ Compatibility สำหรับ
mysql-async
ghmattimysql
และ oxmysql สามารถ Provide Functionality สำหรับ Resource Names เหล่านี้ได้
Current README ยังระบุ Support สำหรับ Syntax ของทั้งสองระบบ
นี่ช่วยให้ Resources เก่าหลายตัว Migration ได้ง่ายขึ้น
53. ต้องเปิด mysql-async พร้อม oxmysql ไหม
Current Documentation ระบุว่าสามารถลบ
mysql-async
ghmattimysql
แล้วให้ oxmysql Provide Compatibility ได้
ดังนั้นโดยทั่วไปไม่ควรรัน Database Wrapper หลายตัวซ้อนโดยไม่มีเหตุผล
ควรมี Database Resource หลักที่ชัดเจน
54. Compatibility หมายความว่า Script เก่าทุกตัวทำงาน 100% หรือไม่
ไม่ควรสรุปแบบนั้น
แม้ oxmysql รองรับ Syntax/Compatibility จำนวนมาก แต่ Script เก่ามากอาจมี
API Assumptions
Deprecated Calls
SQL Syntax เก่า
MySQL-version-specific behavior
ที่ยังต้องแก้
ดังนั้น Migration ต้องทดสอบ Resource จริง
55. mysql-async Syntax รุ่นเก่ายังพบได้
เช่น
MySQL.Async.fetchAll(...)
หรือ
MySQL.Sync.fetchAll(...)
oxmysql มี Compatibility Aliases สำหรับ Calls หลายแบบ
แต่สำหรับ Script ใหม่ควรใช้ Current API ที่อ่านชัดกว่า เช่น
MySQL.query.await(...)
56. ทำไมไม่ควรใช้ Sync เป็นคำอธิบายแบบเก่า
คำว่า
Sync
ใน APIs รุ่นเก่าอาจทำให้เข้าใจว่าทำ Blocking Database Call แบบดั้งเดิม
แต่ Current Lua API ใช้
.await
เพื่อสื่อ Async/Promise/Coroutine Flow ได้ชัดกว่า
สำหรับ Code ใหม่จึงนิยมรูปแบบ
MySQL.query.await(...)
มากกว่า Legacy Aliases
57. oxmysql รองรับ JavaScript หรือไม่
รองรับ
สามารถใช้ Raw Exports หรือ Package
@overextended/oxmysql
สำหรับ JavaScript/TypeScript
ตัวอย่างแนวคิด
const result = await MySQL.query(
'SELECT * FROM users WHERE id = ?',
[id]
)
ดังนั้น oxmysql ไม่ได้จำกัดเฉพาะ Lua Scripts
58. Upsert คืออะไร
บางระบบต้องการ
ถ้ามี Record
→ Update
ถ้ายังไม่มี
→ Insert
Current Documentation แนะนำใช้ Database Constraint และ
INSERT ... ON DUPLICATE KEY UPDATE
ใน Use Case ที่เหมาะสม
แทน
SELECT ก่อน
↓
ถ้ามี UPDATE
ถ้าไม่มี INSERT
ซึ่งสร้าง Queries เพิ่มโดยไม่จำเป็น
59. ทำไมไม่ควรใช้ REPLACE INTO แบบสุ่ม
Current Documentation ชี้ว่า ON DUPLICATE KEY UPDATE มีข้อดีตรงที่ไม่ต้อง
DELETE ROW
↓
INSERT ROW ใหม่
แบบ Behavior ของ REPLACE INTO
เรื่องนี้สำคัญเมื่อ Record มี
Foreign Keys
IDs
Relations
ที่ไม่ควรถูกลบแล้วสร้างใหม่โดยไม่ตั้งใจ
60. ทำไม oxmysql ถึงสำคัญกับ Economy Server
Economy Server มี Transactions จำนวนมาก
เช่น
เงินสด
Bank
Shops
Businesses
Vehicles
Houses
Inventory
Crafting
Market
ทั้งหมดต้องมี Data Consistency
oxmysql ให้ APIs เช่น
query
single
scalar
insert
update
prepare
transaction
ทำให้ Scripts เข้าถึง Database ผ่าน Interface กลาง
แต่ความถูกต้องของ Economy ยังขึ้นกับ SQL/Server Logic ที่ Developer เขียนด้วย
oxmysql ไม่ได้ทำให้ SQL ดีอัตโนมัติ
ถึงใช้ oxmysql
Query แบบนี้ก็ยังไม่ดี
Query ทุก Frame
SELECT * ทั้ง Table
ไม่มี Index
โหลดข้อมูลหลายหมื่น Row โดยไม่จำเป็น
Database Resource ไม่สามารถแก้ Query Design ที่ผิดได้ทั้งหมด
Developer ยังต้องเข้าใจ
SQL
Indexes
Transactions
Schema
Caching
พื้นฐาน
อย่า Query Database ทุก Frame
ไม่ควรมี
while true do
Wait(0)
MySQL.query.await(...)
end
เพื่อเช็กข้อมูล Player ทุก Frame
Database เหมาะกับ Persistent Data ไม่ใช่เป็น Replacement ของ Runtime Memory
ควรโหลดข้อมูลที่จำเป็นแล้ว Cache/เก็บ State ตาม Architecture ของ Framework
Database กับ Runtime State ต่างกันอย่างไร
ตัวอย่าง
Player Online
↓
Framework Player Object
↓
Runtime State
ส่วน Database
Persistent Storage
Framework มักเก็บ Player Data ที่ใช้งานบ่อยไว้ใน Memory แล้ว Save ลง Databaseตามจังหวะ
ไม่ควร Query DB ทุกครั้งที่ต้องดู Job หรือยอดเงินหาก Framework มี API สำหรับข้อมูลนั้นอยู่แล้ว
อย่า Direct SQL แก้ Framework Data ขณะ Player Online โดยไม่จำเป็น
เช่น
UPDATE players
SET job = 'police'
WHERE citizenid = ...
Database อาจเปลี่ยน แต่ Framework Runtime State ยังเป็น Job เดิม
จึงเกิด
Database = police
Runtime = unemployed
ควรใช้ Framework API สำหรับ Gameplay State แล้วให้ Framework จัด Persistence
Direct SQL เหมาะกับงานที่ Architecture ออกแบบไว้จริง
oxmysql กับ ox_inventory เกี่ยวกันอย่างไร
ox_inventory ใช้ oxmysql เป็น Dependency หลัก
Architecture
ox_inventory
↓
oxmysql
↓
Database
เพื่อบันทึก Persistent Data เช่น Stashes และข้อมูลที่เชื่อมกับ Framework/Vehicle Storage
ถ้า oxmysql ใช้งานไม่ได้ Inventory Persistence ก็ได้รับผลกระทบ
oxmysql กับ ox_lib ต่างกันอย่างไร
oxmysql
Database Interface
ox_lib
Library / UI / Utilities
สอง Resource ไม่ได้ทำหน้าที่แทนกัน
Server อาจใช้ทั้งคู่ เช่น
oxmysql
+
ox_lib
+
qbx_core
+
ox_inventory
oxmysql กับ Framework ต่างกันอย่างไร
Framework คือ
Player
Character
Job
Money
Groups
Gameplay APIs
oxmysql คือ
SQL Communication Layer
ตัวอย่าง
Qbox
↓
oxmysql
↓
MariaDB
อย่าสั่ง oxmysql ให้ SetJob โดยตรงเมื่อ Framework มี API สำหรับ SetJob
Server ควร Start oxmysql ตอนไหน
ควร Start ก่อน Resources ที่ต้องใช้ Database
ตัวอย่าง
set mysql_connection_string "mysql://fivem:password@127.0.0.1/fivem"
ensure oxmysql
ensure ox_lib
ensure qbx_core
ensure ox_target
ensure ox_inventory
หรือ ESX
ensure oxmysql
ensure es_extended
ตาม Dependency ของ Stack จริง
ถ้า oxmysql ไม่ Start จะเกิดอะไร
Framework/Resources ชั้นบนอาจเจอ
Missing dependency
Database not ready
Query error
Player data ไม่โหลด
Character เข้าไม่ได้
Inventory ไม่ Save
Vehicle ไม่ Save
ดังนั้นหาก Server Error หลายระบบพร้อมกัน ควรตรวจ Database Layer ก่อน
Checklist ตรวจ oxmysql
Database
MariaDB ทำงาน
Database มีอยู่
DB User ถูก
Password ถูก
Permissions ถูก
Connection
mysql_connection_stringถูกHost ถูก
Port ถูก
Database Name ถูก
Resource
Folder ชื่อ
oxmysqlใช้ Current Release
Resource Start สำเร็จ
Start Order
oxmysql
↓
Framework/Resources ที่ต้องใช้ DB
SQL
Tables มี
Columns ตรง
Schema Version ตรง
Parameters ถูก
Performance
ไม่มี Query Loop หนัก
มี Index ที่เหมาะสม
ไม่ SELECT ข้อมูลเกินจำเป็น
ตาราง Functions สำคัญของ oxmysql
| Function | เหมาะกับ |
|---|---|
MySQL.query | ดึง Rows หรือ Query ทั่วไป |
MySQL.single | ดึง Row เดียว |
MySQL.scalar | ดึงค่าเดียว |
MySQL.insert | Insert และรับ Insert ID |
MySQL.update | Update/Delete และรับจำนวน Rows ที่กระทบ |
MySQL.prepare | Prepared execution |
MySQL.transaction | หลาย Queries ที่ต้องสำเร็จร่วมกัน |
เลือกให้ตรงกับ Intent ของ Query จะทำให้ Code อ่านง่ายกว่า
ตัวอย่าง Resource ใช้ oxmysql แบบพื้นฐาน
fxmanifest.lua
fx_version 'cerulean'
game 'gta5'
server_script '@oxmysql/lib/MySQL.lua'
server_script 'server.lua'
dependency 'oxmysql'
server.lua
RegisterCommand('dbtest', function(source)
local row = MySQL.single.await(
'SELECT ? AS message',
{ 'oxmysql ทำงานแล้ว' }
)
if row then
print(row.message)
end
end, true)
เหมาะสำหรับทดสอบว่า Lua Resource มองเห็น MySQL Interface แล้ว
ตัวอย่างค้นหา Character
local character = MySQL.single.await(
'SELECT `firstname`, `lastname` FROM `characters` WHERE `id` = ? LIMIT 1',
{ characterId }
)
if not character then
return
end
print(character.firstname, character.lastname)
ใช้ Parameters แยกออกจาก Query String
ตัวอย่างนับรถ
local vehicleCount = MySQL.scalar.await(
'SELECT COUNT(*) FROM `vehicles` WHERE `owner` = ?',
{ owner }
)
print(vehicleCount)
ถ้าต้องการแค่จำนวน scalar เหมาะกว่าดึง Rows ทั้งหมดมา Count ใน Lua
ตัวอย่าง Insert
local id = MySQL.insert.await(
'INSERT INTO `vehicles` (`owner`, `plate`) VALUES (?, ?)',
{
owner,
plate
}
)
if not id then
return
end
print(('Vehicle ID: %s'):format(id))
ตัวอย่าง Update
local affected = MySQL.update.await(
'UPDATE `vehicles` SET `stored` = ? WHERE `id` = ?',
{
true,
vehicleId
}
)
if affected == 0 then
print('Vehicle not found')
end
ทำให้ตรวจได้ว่า Query แก้ Record จริงหรือไม่
ตัวอย่าง Transaction สำหรับซื้อรถ
แนวคิด
ตรวจ Player
↓
ตรวจราคา
↓
Transaction
├── หักเงิน
└── สร้างรถ
↓
Success
ช่วยให้ข้อมูลสองส่วนสัมพันธ์กัน
แต่ในระบบเงินจริงควรออกแบบเงื่อนไข SQL ให้ป้องกันยอดติดลบและ Concurrent Transactions อย่างถูกต้องด้วย
ข้อผิดพลาดที่พบบ่อย
Access denied
ตรวจ
Username
Password
Privileges
Connection refused
ตรวจ
MariaDB
Host
Port
Firewall
Unknown database
ตรวจชื่อ Database
Unknown table
Import SQL/Schema ถูกหรือไม่
Unknown column
Framework/Schema Version ตรงหรือไม่
MySQL is nil
ตรวจ
server_script '@oxmysql/lib/MySQL.lua'
และ Start Order
Query ช้า
ตรวจ
SQL
Indexes
Rows
Database Performance
ไม่ใช่ Reinstall oxmysql เป็นอย่างแรก
oxmysql เหมาะกับ Production หรือไม่
เหมาะและถูกใช้อย่างแพร่หลายใน FiveM Frameworks ปัจจุบัน
แต่ Production Setup ควรมี
Dedicated MariaDB
Strong DB Password
Database User แยก
Firewall
Backups
Indexes
Monitoring
Test Server
ไม่ใช่เพียงติดตั้ง Resource แล้วถือว่า Database Infrastructure เสร็จ
Database Backup สำคัญแค่ไหน
สำคัญมาก
เพราะ Database เก็บข้อมูลที่ผู้เล่นใช้เวลาสะสมเป็นเดือนหรือปี
เช่น
Character
Money
Vehicles
Houses
Businesses
Inventory
Phone
ควรมี Automated Backup และทดสอบ Restore ด้วย
Backup ที่ Restore ไม่ได้ไม่ใช่ Backup ที่เชื่อถือได้
สรุป oxmysql คืออะไร ทำไม FiveM ต้องใช้
oxmysql คือ FiveM/FXServer Resource สำหรับสื่อสารกับ MySQL-compatible Database โดยใช้ node-mysql2
มันทำหน้าที่เป็น Layer
FiveM Resource
↓
oxmysql
↓
MariaDB / MySQL
ไม่ใช่ Database Server เอง
Current Documentation แนะนำ MariaDB สำหรับ FiveM และไม่แนะนำให้ติดตั้ง XAMPP เพียงเพื่อใช้ Database Server
สำหรับ Lua Resource สามารถ Import ด้วย
server_script '@oxmysql/lib/MySQL.lua'
แล้วใช้ APIs สำคัญ เช่น
MySQL.query
MySQL.single
MySQL.scalar
MySQL.insert
MySQL.update
MySQL.prepare
MySQL.transaction
โดยรูปแบบ .await ทำให้เขียน Async Database Logic ใน Lua ได้อ่านง่ายขึ้น
oxmysql ยังมี Compatibility กับ mysql-async และ ghmattimysql ซึ่งช่วยในการใช้งาน Resources รุ่นเก่า แต่สำหรับ Code ใหม่ควรใช้ Current APIs และ Parameterized Queries มากกว่า Legacy Syntax
สิ่งสำคัญคือ FiveM ไม่ได้ “ต้องใช้ oxmysql” ทุก Server หากไม่มี Persistent Database แต่ Server RP ปัจจุบันที่ใช้ ESX, QBCore, Qbox, ox_core, Inventory, Phone, Housing หรือ Economy Systems จำนวนมากมักต้องมี Database Layer และ Framework เหล่านี้จำนวนมากเลือกใช้ oxmysql
แนวทางของ comsiam คือให้มอง oxmysql เป็น Infrastructure Layer ไม่ใช่ Gameplay Script ถ้า Player เข้าไม่ได้, Inventory ไม่ Save, รถหาย หรือ Character โหลดไม่ได้ และหลายระบบมี SQL Error พร้อมกัน ให้ตรวจ MariaDB → Connection String → oxmysql ก่อนไล่แก้ Framework ชั้นบน
สำหรับ Production comsiam แนะนำให้ให้ความสำคัญกับ SQL Design พอ ๆ กับตัว oxmysql เอง เพราะ Database Resource ที่ดีไม่สามารถแก้ SELECT * จำนวนมหาศาล, Query ทุก Frame, Missing Index หรือ Transaction Logic ที่ผิดได้ การใช้ Parameters, Indexes, Transactions และ Framework APIs ให้ถูกจึงเป็นหัวใจของ FiveM Server ที่เสถียรในระยะยาว
Comments
Post a Comment