So, auch mal was kleines von mir - ne Resource
Okay, macht nicht viel, nur Abfragen auf die Datenbank. Und das ist ja schonmal was. Braucht ryden's MySQL-Plugin und sonst nur noch ne kleine Änderung in der settings.xml - wenn die vorher nur aus <settings/> bestand, einfach das übernehmen und anpassen, ansonsten halt nur die <setting name=...> nehmen.
<settings>
<!-- MySQL Configuration -->
<setting name="@sql.user" value="username"/>
<setting name="@sql.password" value="password"/>
<setting name="@sql.database" value="database"/>
<setting name="@sql.hostname" value="localhost"/>
<setting name="@sql.port" value="3306"/>
</settings>
So, mal angenommen die Resource ist jetzt in der mtaserver.conf drinne (oder einfach so gestartet), dann gibts ne Reihe von Funktionen, die jetzt zur Verfügung stehen - um mysql_free_result oder ähnliches braucht man sich keine Sorgen mehr zu machen.
sql:create_table
Zum Beispiel können wir ja mal ne Tabelle erstellen:
exports.sql:create_table( 'teleports',
{
{ name = 'teleportID', type = 'int(10) unsigned', auto_increment = true, primary_key = true },
{ name = 'aX', type = 'float' },
{ name = 'aY', type = 'float' },
{ name = 'aZ', type = 'float' },
{ name = 'aInterior', type = 'tinyint(3) unsigned' },
{ name = 'aDimension', type = 'int(10) unsigned' },
{ name = 'bX', type = 'float' },
{ name = 'bY', type = 'float' },
{ name = 'bZ', type = 'float' },
{ name = 'bInterior', type = 'tinyint(3) unsigned' },
{ name = 'bDimension', type = 'int(10) unsigned' },
}
)
Alles anzeigen
Ist garnicht schwer:
- name ist immer der Name der Tabellenspalte an
- type der typ (z.b. float für Floats - Koordinaten z.b., int(10) für ganze Zahlen, int(10) unsigned für ganze Zahlen ohne Vorzeichen (d.h. immer positiv), text für Text und so weiter. Gibt im Netz genug Zeugs, was MySQL-Datentypen erklärt, einfach mal suchen.
- null = true würde angeben, dass die Werte in der Spalte auch gerne NULL sein dürfen (wird von der resource als nil zurückgegeben)
- primary_key = true für den Primary Key, das is meistens ne eindeutige ID, können auch mehrere Spalten mit primary_key sein.
- auto_increment - wenn's auf true ist, dann hat die Spalte eine ID, die sich bei jedem einfügen um 1 erhöht, wenn's auf ner x-beliebigen Zahl gesetzt ist, dann wird das als Grundwert für's auto_increment genommen, d.h. wird ab da gezählt.
Insgesamt nicht sonderlich schwer, kann man z.b. in onResourceStart aufrufen.
Rückgabewerte sind:
- true, true wenn die Tabelle erfolgreich erstellt wurde
- true, false wenn die Tabelle existiert und keine Änderungen notwending sind oder erfolgreich modifiziert wurde (wenn man ne Spalte hinzufügt oder ändert)
- false wenn's n Fehler gab.
Nun brauch man ja Tabellen nicht allzu oft erstellen, widmen wir uns mal lieber Abfragen, dafür gibt's genau vier Funktionen:
sql:query_free
Ist nicht ganz so schwer, ist einfach ne beliebige Datenbank-Abfrage. Gibt true zurück wenns erfolgreich war, sonst false
Im Beispiel können wir ja mal einen Teleporter (DB-Struktur von oben) löschen:
oder wenn wir Fehler beachten wollen (wollen wir!):
if exports.sql:query_free( "DELETE FROM teleports WHERE teleportID = 123" ) then
-- Code falls die Abfrage erfolgreich war, z.b. die Objekte im Spiel löschen, ne Meldung ausgeben und so weiter.
else
-- Code falls die Abfrage fehlgeschlagen ist, z.b. ne Fehlermeldung
end
sql:query_assoc
Führt ne Abfrage aus (im Normalfall SELECT), die Ergebnisse zurückgibt, mehrere Spalten und Zeilen möglicherweise. Gibt ne Tabelle zurück (oder false, wenn's n Fehler gab).
local result = exports.sql:query_assoc( "SELECT * FROM teleports" )
if result then
for key, value in ipairs( result ) do
-- An dieser Stelle gibt es jetzt für jedes Feld in der Datenbank das dazugehörige Feld in der Tabelle, z.b.
-- value.teleportID, value.aX, value.aY und so weiter.
-- Alle Felder haben automatisch den Typ in Lua, der am sinnvollsten ist:
-- Integer- und Float-Werte sind in number konvertiert, NULL ist nil, sonst ist alles string.
-- Wir könnten jetzt z.b. Marker erstellen, je nach dem was man halt grade brauch.
createMarker( value.aX, value.aY, value.aZ )
-- und so weiter.
end
end
Alles anzeigen
sql:query_assoc_single
Führt ne Abfrage aus, die entweder eine oder keine Zeile zurückgibt. Wenn's eine Zeile ist, dann gibt es ne Tabelle mit Feldern zurück, sonst false. Ist ähnlich zu query_assoc, braucht man jedoch keine Schleife dafür.
local result = exports.sql:query_assoc( "SELECT * FROM teleports WHERE teleportID = 123" )
if result then
createMarker( result.aX, result.aY, result.aZ )
-- und so weiter
end
sql:query_insertid
Fügt ne INSERT-Abfrage aus und gibt - falls diese erfolgreich war - die Insert-ID zurück (auto_increment un so)
Zum Beispiel in obiger Abfrage:
local insertid = exports.sql:query_insertid( "INSERT INTO teleports (`aX`, `aY`, `aZ`, `aInterior`, `aDimension`, `bX`, `bY`, `bZ`, `bInterior`, `bDimension`) VALUES (...)" )
if insertid then
-- irgendwas mit der ID machen
end
kleine Tipps am Rande
Alle query-Funktionen können bei Bedarf Escape-Zeichen in Strings einfügen (sollte man machen), dazu einfach '%s' in den Query schreiben und dann als Parameter ergänzen, das wird dann automatisch ersetzt:
exports.sql:query_free( "DELETE FROM accounts WHERE username = '%s' AND passwort = '%s'", username, passwort )
Im Vergleich:
exports.sql:query_free( "DELETE FROM accounts WHERE username = '" .. exports.sql:escape_string( username ) .. "' AND passwort = '" .. exports.sql:escape_string( passwort ) .. "'" )
Und was ich bei INSERT zumindest immer ganz nützlich fand, ist table.concat für die einzelnen Felder:
local vehicleID = exports.sql:query_insertid( "INSERT INTO vehicles (model, posX, posY, posZ, rotX, rotY, rotZ, numberplate, color1, color2, interior, dimension) VALUES (" .. table.concat( { model, x, y, z, 0, 0, rz, '"%s"', color1, color2, interior, dimension }, ", " ) .. ")", getVehiclePlateText( vehicle ) )
Statt:
local vehicleID = exports.sql:query_insertid( "INSERT INTO vehicles (model, posX, posY, posZ, rotX, rotY, rotZ, numberplate, color1, color2, interior, dimension) VALUES (" .. model .. ", " .. x .. ", " .. y .. ", " .. z .. ", 0, 0, " .. rz .. ", '%s', " .. color1 .. ", " .. color2 ..", " .. interior .. ", " .. dimension)", getVehiclePlateText( vehicle ) )
Download
Im Anhang, gibts auch über Git(Hub): Link