$ ABD Doları
  • $ ABD Doları
  • € AVRO
  • £ GBP
  • $ Avustralya Doları
  • R$ BRL
  • İsviçre Frangı İsviçre Frangı
  • ¥ Japon Yeni
mysql async oxmysql

mysql-async'ten oxmysql'e: Güvenli Geçiş ve Sorgu P…

Kitle: FiveM sunucu sahipleri, betik yazarları, bakımcılar
Amaç: Yer değiştirmek mysql-async ile oxmysql güvenli bir şekilde, sorguları hızlandırın ve SQL kullanımınızı modernleştirin.

Ayrıca şunu da okuyun:


Özetle;

  • Kullanmak oxmysql: hazırlanmış ifadeler, promise\/await API, daha iyi tanılama, güçlü performans.
  • Minimum kod değişiklikleri: değiştir @param? (konumsal) veya :name (adlandırılmış) parametreler; değiştirin MySQL.Async.* çağrıları ile MySQL.*/exports.oxmysql:*.
  • SQL “UP” betiklerini çalıştırın aşağıda (karakter seti\/indeks düzeltmeleri) ve rollback hazır.
  • Mikro kıyaslama aracı ile doğrulayın sonunda, donanımınızdaki kazançları onaylamak için.

1) Uçuş Öncesi Güvenlik Kontrol Listesi

  1. Tam yedekleme: mysqldump --single-transaction yourdb > backup.sql.
  2. Staging ortamı üretim şemasını ve veri alt kümesini yansıtma.
  3. Yapı & bağımlılıklar: Mevcut FXServer yapısı, en son oxmysql.
  4. Kesinti penceresi üretim geçişi için (genellikle < 5 dakika).
  5. Sağlık kontrolleri hazır: /players, giriş akışı, ekonomi işlemleri, garaj işlemleri, envanter işlemleri, yasak kontrolleri.

2) Kurulum ve Bağlantı oxmysql

2.1 server.cfg

# Stop using mysql-async
default_prio 500
# ensure mysql-async # ← comment out or remove

# Start oxmysql
default_prio 50
ensure oxmysql

# Connection string consumed by oxmysql
set mysql_connection_string "mysql://user:pass@127.0.0.1:3306/yourdb?charset=utf8mb4"

# Optional diagnostics
set mysql_slow_query_warning 200 # log queries slower than 200ms
set mysql_debug false # true for verbose logging during staging

Kale mysql-async devre dışı ancak hazırlık aşamasında kaynaklar klasörünüzde mevcut (hızlı geri alma için).

3) API Eşleme: mysql‑async → oxmysql

mysql-async (eski):

  • Async: MySQL.Async.fetchAll, MySQL.Async.fetchScalar, MySQL.Async.execute
  • Senkronizasyon: MySQL.Sync.fetchAll, MySQL.Sync.fetchScalar, MySQL.Sync.execute
  • Parametreler: @param tabloları şu şekilde biçimlendir { ['@identifier']=identifier }

oxmysql (modern):

  • Geri çağırma stili ile export: exports.oxmysql:query|scalar|single|insert|update(sql, params, cb)
  • Promise/await ile global: MySQL.query|scalar|single|insert|update.await(sql, params) ve await olmayan geri çağırmalar .await
  • Parametreler: konumsal ? dizi ile veya adlandırılmış :name nesne ile

3.1 Yaygın değişiklikler

SELECT çoklu

-- mysql-async
MySQL.Async.fetchAll(
 'SELECT * FROM users WHERE identifier = @id',
 { ['@id'] = identifier },
 function(rows) ... end
)

-- oxmysql (callback via export)
exports.oxmysql:query(
 'SELECT * FROM users WHERE identifier = ?',
 { identifier },
 function(rows) ... end
)

-- oxmysql (await)
local rows = MySQL.query.await(
 'SELECT * FROM users WHERE identifier = ?',
 { identifier }
)

SELECT tek satır

-- mysql-async (fetchAll + rows[1])

-- oxmysql
local row = MySQL.single.await(
 'SELECT * FROM users WHERE identifier = ?',
 { identifier }
)

SELECT skaler (örneğin, count, id)

-- mysql-async

-- oxmysql
local count = MySQL.scalar.await(
 'SELECT COUNT(*) FROM owned_vehicles WHERE owner = ?',
 { owner }
)

SOKMAK (insertId al)

-- mysql-async (execute)

-- oxmysql
local insertId = MySQL.insert.await(
 'INSERT INTO notes (owner, text) VALUES (?, ?)',
 { cid, text }
)

UPDATE/DELETE (etkilenenSatırlar)

-- mysql-async (execute)

-- oxmysql
local changed = MySQL.update.await(
 'UPDATE users SET job = ?, job_grade = ? WHERE identifier = ?',
 { job, grade, identifier }
)

İşlemler (manuel)

-- oxmysql manual transaction
MySQL.query.await('START TRANSACTION')
local ok = true

local r1 = MySQL.update.await('UPDATE users SET bank = bank - ? WHERE identifier = ? AND bank >= ?', { amount, fromId, amount })
local r2 = MySQL.update.await('UPDATE users SET bank = bank + ? WHERE identifier = ?', { amount, toId })

if r1 == 1 and r2 == 1 then
 MySQL.query.await('COMMIT')
else
 MySQL.query.await('ROLLBACK')
end

Bazı çerçeveler sarmalayıcılar sunar (örneğin, ox_lib) ekleyen MySQL.ready, .transaction, vb. Yukarıdaki çağrılar ek sarmalayıcılara gerek kalmadan güvenlidir.

4) Hazır İfadeler Hile Sayfası

Parametre stilleri

  • mysql‑async (eski): @name bir tablo ile yer tutucular: { ['@name']=value }
  • oxmysql (konumsal): ? yer tutucular bir dizi: { value1, value2 }
  • oxmysql (adlandırılmış): :name yer tutucular bir nesne: { name = value }

Örnekler

-- Named params (recommended for readability)
local row = MySQL.single.await(
 'SELECT * FROM users WHERE identifier = :id',
 { id = identifier }
)

-- IN (...) list
-- Build placeholders dynamically and pass a flat array
local ids = { 'cid1','cid2','cid3' }
local qs = ('?,' ):rep(#ids):sub(1,-2) -- "?, ?, ?"
local rows = MySQL.query.await('SELECT * FROM players WHERE citizenid IN ('..qs..')', ids)

-- JSON fields (MySQL 5.7+/MariaDB 10.2+)
local name = MySQL.scalar.await('SELECT JSON_UNQUOTE(JSON_EXTRACT(data, "$.name")) FROM players WHERE citizenid = ?', { cid })

Yapmak

  • Kullanmak hazır ifadeler her yerde (kullanıcı girdisini asla string birleştirmeyin).
  • Tercih etmek adlandırılmış parametreler karmaşık ifadelerde netlik için.
  • Eklemek LIMIT 1 tek bir varlık okunurken.

Kaçınmak

  • Joker karakter SELECT * sık erişilen yollarda (gerekli sütunları seçin).
  • Satır başına N+1 sorgular; toplu işlem yapın IN (...) IN (...).

5) Veritabanı “UP” Geçişi Scripts (Çalıştırılmaya Hazır)

Çerçevenize (ESX/QBCore) ve sunucunuza (MySQL 8+ veya MariaDB 10.4+) uygun blokları seçin. Önce hazırlık sunucusunda çalıştırın.

5.1 Karakter Setini ve Karşılaştırmayı Normalleştirin (Her yerde UTF‑8)

(A) MySQL 8+ — değiştirin yourdb bir kez

-- Force database default to utf8mb4 (emoji‑safe)
ALTER DATABASE `yourdb` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;

-- Convert common tables (extend list as needed)
ALTER TABLE `users` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `owned_vehicles` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `players` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `player_vehicles` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

(B) MariaDB 10.4+ — aynı ifadeler geçerlidir.

Diğer sık kullanılan tabloları (envanter, fatura, telefon, topluluk, işler) sunucunuzda bulunan şekilde ekleyin.

5.2 ESX İndeksler (güvenli performans kazanımları)

MySQL 8+

ALTER TABLE `users`
 ADD INDEX IF NOT EXISTS `idx_users_identifier` (`identifier`),
 ADD INDEX IF NOT EXISTS `idx_users_job` (`job`),
 ADD INDEX IF NOT EXISTS `idx_users_name` (`name`);

ALTER TABLE `owned_vehicles`
 ADD UNIQUE INDEX IF NOT EXISTS `ux_owned_vehicles_plate` (`plate`),
 ADD INDEX IF NOT EXISTS `idx_owned_vehicles_owner` (`owner`);

MariaDB 10.4+

-- Drop first to be idempotent where IF NOT EXISTS is unavailable
DROP INDEX IF EXISTS `idx_users_identifier` ON `users`;
DROP INDEX IF EXISTS `idx_users_job` ON `users`;
DROP INDEX IF EXISTS `idx_users_name` ON `users`;
CREATE INDEX `idx_users_identifier` ON `users` (`identifier`);
CREATE INDEX `idx_users_job` ON `users` (`job`);
CREATE INDEX `idx_users_name` ON `users` (`name`);

DROP INDEX IF EXISTS `ux_owned_vehicles_plate` ON `owned_vehicles`;
DROP INDEX IF EXISTS `idx_owned_vehicles_owner` ON `owned_vehicles`;
CREATE UNIQUE INDEX `ux_owned_vehicles_plate` ON `owned_vehicles` (`plate`);
CREATE INDEX `idx_owned_vehicles_owner` ON `owned_vehicles` (`owner`);

5.3 QBCore/QBOX İndeksleri

MySQL 8+

ALTER TABLE `players`
 ADD UNIQUE INDEX IF NOT EXISTS `ux_players_citizenid` (`citizenid`),
 ADD INDEX IF NOT EXISTS `idx_players_license` (`license`),
 ADD INDEX IF NOT EXISTS `idx_players_steam` (`steam`),
 ADD INDEX IF NOT EXISTS `idx_players_last_name` (`lastname`);

ALTER TABLE `player_vehicles`
 ADD UNIQUE INDEX IF NOT EXISTS `ux_player_vehicles_plate` (`plate`),
 ADD INDEX IF NOT EXISTS `idx_player_vehicles_citizenid` (`citizenid`);

MariaDB 10.4+

DROP INDEX IF EXISTS `ux_players_citizenid` ON `players`;
DROP INDEX IF EXISTS `idx_players_license` ON `players`;
DROP INDEX IF EXISTS `idx_players_steam` ON `players`;
DROP INDEX IF EXISTS `idx_players_last_name` ON `players`;
CREATE UNIQUE INDEX `ux_players_citizenid` ON `players` (`citizenid`);
CREATE INDEX `idx_players_license` ON `players` (`license`);
CREATE INDEX `idx_players_steam` ON `players` (`steam`);
CREATE INDEX `idx_players_last_name` ON `players` (`lastname`);

DROP INDEX IF EXISTS `ux_player_vehicles_plate` ON `player_vehicles`;
DROP INDEX IF EXISTS `idx_player_vehicles_citizenid` ON `player_vehicles`;
CREATE UNIQUE INDEX `ux_player_vehicles_plate` ON `player_vehicles` (`plate`);
CREATE INDEX `idx_player_vehicles_citizenid` ON `player_vehicles` (`citizenid`);

5.4 İsteğe Bağlı: ox_inventory (kuruluysa)

ALTER TABLE `ox_inventory`
 ADD INDEX IF NOT EXISTS `idx_inv_owner` (`owner`),
 ADD INDEX IF NOT EXISTS `idx_inv_type` (`type`);

ALTER TABLE `ox_inventory_items`
 ADD INDEX IF NOT EXISTS `idx_items_inv_owner_name` (`inventory`, `owner`, `name`);

Şemanız farklıysa tablo adlarını ayarlayın (bazı kurulumlar kullanır inventories / items).

6) Geri Alma Planı (Sıfır Panik)

6.1 Kod geri alma

  1. Kaynak değişikliklerinizi geri alın (bir tane saklayın legacy-mysql-async dal).
  2. İçinde server.cfg takas: # ensure oxmysql ensure mysql-async
  3. FXServer'ı veya etkilenen kaynakları bağımlılık sırasına göre yeniden başlatın.

6.2 SQL geri alma

  • Yalnızca indeksler eklendi), kaldırın (bkz. MariaDB yukarıdaki bloklar — kullanın DROP INDEX IF EXISTS).
  • Eğer siz karakter kümesi/karşılaştırması değiştirildi ve geri almalı, veritabanını ve tabloları geri yüklemelidir:
ALTER DATABASE `yourdb` CHARACTER SET = utf8 COLLATE = utf8_general_ci;
ALTER TABLE `users` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE `owned_vehicles` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE `players` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE `player_vehicles` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;

Şuradan geri yüklemeyi tercih et backup.sql mümkün olduğunda toplu karakter kümesi tersine çevirmeleri yerine.

7) Uçtan Uca Geçiş Prosedürü (Betiklenebilir)

  1. Freeze dağıtımları, DB'yi yedekleyin.
  2. Uygula Bölüm 5 “UP” SQL staging'de doğrulayın → üretime geçin.
  3. Kod değişikliğini kaydet: çağrıları değiştir (Bölüm 3) + parametre stilleri (Bölüm 4).
  4. Dağıtın, ensure oxmysql, sunucuyu yeniden başlat.
  5. Koşmak duman testleri (smoke tests) (giriş, maaş bordroları, envanter, araç oluşturma/yok etme, yasaklar, şirket parası, iş görevi geçişleri).
  6. 15-30 dakika boyunca günlükleri izleyin (mysql_slow_query_warning yardımcı olur); eksik parametreleri veya şema uyumsuzluklarını ele alın.

8) Mikro Karşılaştırmalar (Kendi Sayılarınızı Getirin)

Yol üzerindeki sorguları karşılaştırmak için ekleyebileceğiniz küçük bir kaynak senin donanım ve veri kümesi.

fxmanifest.lua

fx_version 'cerulean'
game 'gta5'
server_script 'bench.lua'

bench.lua

local COUNT = 2000 -- adjust for your server

local function bench(name, fn)
 local t0 = os.clock()
 local ok, err = pcall(fn)
 local dt = (os.clock() - t0) * 1000.0
 print(('[bench] %s: %.2f ms %s'):format(name, dt, ok and '' or ('ERR: '..tostring(err))))
end

-- Hot path 1: ownership lookup
bench('SELECT single', function()
 for i=1,COUNT do
 local row = MySQL.single.await('SELECT owner FROM owned_vehicles WHERE plate = :p LIMIT 1', { p = ('TEST%04d'):format(i % 500) })
 end
end)

-- Hot path 2: batched fetch
bench('SELECT batch IN', function()
 local ids = {}
 for i=1,100 do ids[#ids+1] = ('cid%04d'):format(i) end
 local qs = ('?,' ):rep(#ids):sub(1,-2)
 local rows = MySQL.query.await('SELECT citizenid, firstname, lastname FROM players WHERE citizenid IN ('..qs..')', ids)
end)

-- Hot path 3: update with guard
bench('UPDATE guarded', function()
 for i=1,COUNT do
 local changed = MySQL.update.await('UPDATE users SET bank = bank + :d WHERE identifier = :id AND bank >= 0', { d = 1, id = ('lic:%04d'):format(i % 500) })
 end
end)

Nasıl çalıştırılır

  1. Kaynağı bir klasöre koyun (örneğin, ox-bench/), ekleyin ensure ox-bench ile server.cfg.
  2. Sunucu konsolunu takip edin; sonuçlar şu şekilde satırlar halinde yazdırılır: [bench] SELECT single: 134.21 ms.
  3. Bir önce/sonra karşılaştırma, ile bir kez çalıştırın mysql-async (gerekirse çağrıları ayarla), sonra oxmysql.

Nelere dikkat etmeli

  • Taşınmadan sonra bölüm başına toplam ms'yi düşürün.
  • Sorgulara bağlı oyun eylemlerinde daha düşük P95/P99 gecikmesi.
  • Bir saatlik canlı oyun boyunca daha az yavaş sorgu uyarısı.

9) Sorun Giderme

S: “no such export: query/single/…” hatası alıyorum.
A: oxmysql yeterince erken başlatılmamış. Emin olun ensure oxmysql onu kullanan kaynakların üzerindedir.

S: Parametre hataları veya boş sonuçlar.
C: Muhtemelen tuttunuz @param yer tutucular. Şununla değiştirin ? veya :name ve buna göre bir dizi/nesne geçirin.

S: Kilitlenmeler veya kısmi yazmalar.
C: Çok adımlı bakiyeleri/transferleri bir işlem içine alın (Bölüm 3'e bakın), Bölüm 5'teki dizinleri ekleyin.

S: JSON yolu NULL döndürüyor.
C: Motorunuzun JSON fonksiyonlarını (MySQL ≥5.7/MariaDB ≥10.2) desteklediğini ve sütun türünün JSON (Olumsuz LONGTEXT).

S: Taşıma sonrası yavaş.
C: Eksik indeksleri kontrol edin, EXPLAIN sorgunuzu, yalnızca gerekli sütunları projelendirin ve Sunucu Optimizasyonu Oyun Kitabı'nı inceleyin.

10) Kod İnceleme Kontrol Listesi (kopyala/yapıştır)

  • Dize birleştirme SQL yok; tüm sorgular parametrelendirildi.
  • Kullanmak .single/.scalar ile LIMIT 1 yalnızca bir satır/değer gerektiğinde.
  • Toplu IN (...) koleksiyonlar için okur.
  • Çok adımlı para/envanter işlemleri etrafındaki işlemler.
  • Her sıcak için dizin mevcut WHERE/JOIN sütun.
  • Kaçınmak SELECT * yoğun yollarda.
  • Yavaş sorguları günlüğe kaydet; en kötü sorumluları haftalık olarak takip edin.

Dahili Bağlantılar


Krediler
fivemx.com tarafından sürdürülmektedir. Katkılar memnuniyetle karşılanır (ek güvenli indekslerin veya sarmalayıcı yardımcıların farklarını gönderin).