+
+
+
Mod_lua implémente une fonctionnalité basique de connexion aux
+bases de données permettant d'envoyer des requêtes ou d'exécuter des
+commandes auprès des moteurs de base de données les plus courants
+(mySQL, PostgreSQL, FreeTDS, ODBC, SQLite, Oracle), ainsi que mod_dbd.
+
+
L'exemple suivant montre comment se connecter à une base de
+données et extraire des informations d'une table :
+
+function handler(r)
+ -- connexion à la base de données
+ local database, err = r:dbacquire("mysql", "server=localhost,user=root,dbname=mydb")
+ if not err then
+ -- Sélection de certaines informations
+ local results, err = database:select(r, "SELECT `name`, `age` FROM `people` WHERE 1")
+ if not err then
+ local rows = results(0) -- extrait tous les enregistrements en mode synchrone
+ for k, row in pairs(rows) do
+ r:puts( string.format("Name: %s, Age: %s<br/>", row[1], row[2]) )
+ end
+ else
+ r:puts("Database query error: " .. err)
+ end
+ database:close()
+ else
+ r:puts("Connexion à la base de données impossible : " .. err)
+ end
+end
+
+
+
+ Pour utiliser mod_dbd
, spécifiez
+mod_dbd
comme type de base de données, ou laissez le champ
+vide :
+
+
+ local database = r:dbacquire("mod_dbd")
+
+
+
+
+
L'objet database renvoyé par dbacquire
possède
+les méthodes suivantes :
+
Sélection normale et requête vers une base de données
+:
+
+-- Exécution d'une requête et renvoie du nombre d'enregistrements
+affectés :
+local affected, errmsg = database:query(r, "DELETE FROM `tbl` WHERE 1")
+
+-- Exécution d'une requête et renvoie du résultat qui peut être utilisé
+en mode synchrone ou asynchrone :
+local result, errmsg = database:select(r, "SELECT * FROM `people` WHERE 1")
+
+
+
Utilisation de requêtes préparées (recommandé) :
+
+-- Création et exécution d'une requête préparée :
+local statement, errmsg = database:prepare(r, "DELETE FROM `tbl` WHERE `age` > %u")
+if not errmsg then
+ local result, errmsg = statement:query(20) -- exécute la requête pour age > 20
+end
+
+-- Extrait une requête préparée depuis une directive DBDPrepareSQL :
+local statement, errmsg = database:prepared(r, "someTag")
+if not errmsg then
+ local result, errmsg = statement:select("John Doe", 123) -- injecte les valeurs "John Doe" et 123 dans la requête
+end
+
+
+
+
Echappement de valeurs, fermeture de la base données,
+etc...
+
+-- Echappe une valeur pour pouvoir l'utiliser dans une requête :
+local escaped = database:escape(r, [["'|blabla]])
+
+-- Ferme une base de données et libère les liens vers cette dernière :
+database:close()
+
+-- Vérifie si une connexion à une base de données est en service et
+opérationnelle :
+local connected = database:active()
+
+
+
+
+
+
Les jeux d'enregistrements renvoyés par db:select
ou par des
+requêtes préparées créées par db:prepare
permettent de
+sélectionner des enregistrements en mode synchrone ou
+asynchrone, selon le nombre d'enregistrements spécifié :
+ result(0)
sélectionne tous les enregistrements en mode
+synchrone en renvoyant une table d'enregistrements.
+ result(-1)
sélectionne le prochain enregistrement disponible en
+mode asynchrone.
+ result(N)
sélectionne l'enregistrement numéro
+N
en mode asynchrone.
+
+
+-- extrait un jeu d'enregistrements via une requête régulière :
+local result, err = db:select(r, "SELECT * FROM `tbl` WHERE 1")
+
+local rows = result(0) -- sélectionne tous les enregistrements en mode synchrone
+local row = result(-1) -- sélectionne le prochain enregistrement disponible en mode asynchrone
+local row = result(1234) -- sélectionne l'enregistrement 1234 en mode asynchrone
+
+
+
Il est possible de construire une fonction qui renvoie une
+fonction itérative permettant de traiter tous les enregistrement en mode
+synchrone ou asynchrone selon la valeur de l'argument async :
+
+
+function rows(resultset, async)
+ local a = 0
+ local function getnext()
+ a = a + 1
+ local row = resultset(-1)
+ return row and a or nil, row
+ end
+ if not async then
+ return pairs(resultset(0))
+ else
+ return getnext, self
+ end
+end
+
+local statement, err = db:prepare(r, "SELECT * FROM `tbl` WHERE `age` > %u")
+if not err then
+ -- sélectionne des enregistrements en mode asynchrone :
+ local result, err = statement:select(20)
+ if not err then
+ for index, row in rows(result, true) do
+ ....
+ end
+ end
+
+ -- sélectionne des enregistrements en mode synchrone :
+ local result, err = statement:select(20)
+ if not err then
+ for index, row in rows(result, false) do
+ ....
+ end
+ end
+end
+
+
+
+
+
+
+
Lorsqu'elles ne sont plus utilisées, les connexions aux bases de
+données doivent être fermées avec database:close()
. Si vous
+ne les fermez pas manuellement, mod_lua les fermera peut-être en tant
+que résidus collectés, mais si ce n'est pas le cas, vous pouvez finir
+pas avoir trop de connexions vers la base de données inutilisées. Les
+deux mesures suivantes sont pratiquement identiques :
+
+
+-- Méthode 1 : fermeture manuelle de la connexion
+local database = r:dbacquire("mod_dbd")
+database:close() -- c'est tout
+
+-- Méthode 2 : on laisse le collecteur de résidus la fermer
+local database = r:dbacquire("mod_dbd")
+database = nil -- on coupe le lien
+collectgarbage() -- fermeture de la connexion par le collecteur de résidus
+
+
+
+
+
+
Bien que les fonctions query
et run
+soient toujours disponibles, il est recommandé d'utiliser des requêtes
+préparées chaque fois que possible, afin d'une part d'optimiser les
+performances (si votre connexion reste longtemps en vie), et d'autre part
+minimiser le risque d'attaques par injection SQL. Les fonctions
+run
et query
ne doivent être utilisées que
+lorsque la requête ne contient pas de variables (requête statique). Dans
+le cas des requêtes dynamiques, utilisez db:prepare
ou
+db:prepared
.
+
+
+