Transactions
Une transaction permet d'executer plusieurs requetes de maniere atomique : soit tout reussit, soit rien n'est applique. C'est indispensable quand tu dois garantir la coherence de tes donnees.
Pourquoi utiliser des transactions ?
Imagine ce scenario : un joueur transfere 1000$ a un autre joueur. Il faut :
- Retirer 1000$ au joueur A
- Ajouter 1000$ au joueur B
Si l'etape 1 reussit mais l'etape 2 echoue (crash, erreur...), le joueur A perd son argent mais le joueur B ne recoit rien. L'argent disparait !
Avec une transaction, si l'etape 2 echoue, l'etape 1 est automatiquement annulee. L'argent est protege.
Comment ca marche
Syntaxe callback (recommandee)
La facon la plus simple : passe une fonction. Le commit est automatique, et en cas d'erreur rien n'est applique.
local success = ORM.transaction(function(tx)
tx:insert("users", { identifier = "license:abc", money = 500 })
tx:update("users", { money = 1000 }, { identifier = "license:def" })
tx:delete("logs", { identifier = "license:old" })
end)
-- Auto-commit a la fin de la fonction !
if success then
print("Transaction reussie !")
else
print("Transaction echouee, tout a ete annule")
end
Syntaxe builder (manuelle)
Tu peux aussi construire la transaction manuellement si tu preferes :
local tx = ORM.transaction()
-- Ajoute des operations (rien n'est execute pour l'instant)
tx:insert("users", { identifier = "license:abc", money = 500 })
tx:update("users", { money = 1000 }, { identifier = "license:def" })
tx:delete("logs", { identifier = "license:old" })
-- Tout est execute d'un coup, de maniere atomique
local success = tx:commit()
:::tip Quelle syntaxe choisir ?
La syntaxe callback est recommandee : elle garantit que tu n'oublieras jamais le commit(). La syntaxe builder est utile si tu dois construire ta transaction dynamiquement (boucles, conditions...).
:::
Les methodes disponibles
Tu peux ajouter n'importe quelle operation a une transaction :
tx:insert(table, data)
tx:insert("users", { identifier = "license:abc", money = 500, job = "police" })
tx:update(table, data, where)
tx:update("users", { money = 0 }, { identifier = "license:abc" })
tx:delete(table, where)
tx:delete("users", { identifier = "license:abc" })
tx:upsert(table, data)
tx:upsert("users", { identifier = "license:abc", money = 2000 })
tx:addRaw(sql, params)
Pour les requetes SQL personnalisees :
tx:addRaw("UPDATE users SET money = money + ? WHERE job = ?", { 100, "police" })
tx:commit() → boolean
Execute toutes les requetes d'un coup. Retourne true si tout a reussi.
tx:getQueries() → table
Retourne la liste des requetes (utile pour le debug).
Exemples concrets
Transfert d'argent
local function transferMoney(fromId, toId, amount)
local tx = ORM.transaction()
-- Retirer l'argent au joueur A
tx:addRaw(
"UPDATE users SET money = money - ? WHERE identifier = ? AND money >= ?",
{ amount, fromId, amount }
)
-- Ajouter l'argent au joueur B
tx:addRaw(
"UPDATE users SET money = money + ? WHERE identifier = ?",
{ amount, toId }
)
local success = tx:commit()
if success then
print(("Transfert de %d$ de %s vers %s reussi"):format(amount, fromId, toId))
else
print("Transfert echoue — aucune modification appliquee")
end
return success
end
Achat d'un vehicule
local function buyVehicle(playerId, vehicleModel, price)
local tx = ORM.transaction()
-- Debiter le joueur
tx:addRaw(
"UPDATE users SET money = money - ? WHERE identifier = ? AND money >= ?",
{ price, playerId, price }
)
-- Creer le vehicule
tx:insert("vehicles", {
owner = playerId,
model = vehicleModel,
plate = GeneratePlate(),
fuel = 100,
})
return tx:commit()
end
Suppression d'un joueur et de ses donnees
local function deletePlayer(identifier)
local tx = ORM.transaction()
tx:delete("vehicles", { owner = identifier })
tx:delete("inventories", { owner = identifier })
tx:delete("user_roles", { user_id = identifier })
tx:delete("users", { identifier = identifier })
return tx:commit()
end
:::tip Quand utiliser une transaction ? Utilise une transaction quand tu modifies plusieurs tables ou plusieurs lignes qui doivent rester coherentes entre elles. Si une seule operation echoue, toutes les autres sont annulees. :::