.-. .--------------. .------------.
.-------. | |---| Pilote Mysql |---| mysqld |
|scripts| | | `--------------' `------------'
| Perl | |D| .--------------. .-------------.
| |----|B|---| Pilote Oracle|---|Moteur Oracle|
|use DBI| |I| `--------------' `-------------'
| | | | .--------------. .-------------.
| | | |---| Postgresql |---| postmaster |
| | | | .--------------. .-------------.
| | | |... autres pilotes
`-------' | |...
#!/usr/bin/perl -w
# charger le module DBI
use DBI;
# fixer la source de données $dns (=database name source) et le compte utilisateur
# (l'utilisateur doit bien sûr avoir les droits d'accès à cette base)
$dsn = "dbi:mysql:cdi";
$login = "admin";
$mdp = "admin";
########################################################################################################
# Se connecter à la source de données (avec ce compte valide sur la base) revient à créer un objet #
# La méthode connect de la classe DBI renvoie une référence vers cet objet, qui est un #
# identifiant de connexion, noté usuellement $dbh (=DataBase Handle). #
# Les méthodes sont appelées suivant la syntaxe usuelle orientée-objet $dbh -> methode #
########################################################################################################
$dbh = DBI->connect($dsn, $login, $mdp) or die "Echec de la connexion\n";
# la soumission d'une requête avec Perl-DBI s'effectue en 3 phases
# 1) La préparation de la requête est assurée par la méthode dbh->prepare
# elle s'applique à la chaine exprimant la requête
# et renvoie un identifiant de requête ($sth = STatement Handle)
# (Certains moteurs effectuent à ce stade une pré-compilation de la requête
# ce n'est pas supporté par Mysql jusqu'ici)
$table = "documents";
# on veut afficher 3 champs de cette table : voici la requête écrite en SQL
$requete = "SELECT titre, auteur, editeur FROM $table ";
$sth = $dbh->prepare($requete);
# 2) on exécute la requête préparée en adressant la méthode execute au descripteur $sth
$sth->execute();
# 3) on s'adresse à $sth pour extraire les données de l'ensemble-résultat, ligne par ligne
# chaque appel à $sth -> fetchrow_array extrait une ligne du résultat et la place dans une liste
# notée ici @enr. Quand toutes les lignes ont été obtenues, on sort de la boucle
while (@enr = $sth -> fetchrow_array) {
print "@enr\n";
}
$sth -> finish;
$dbh -> disconnect;
# meilleure façon, pour afficher les valeurs des champs individuellement
# print "Titre\t Auteur\t Editeur \n";
# while ( ($t, $a, $e) = $sth -> fetchrow_array) {
# printf "%50s %30s %20s\n", $t, $a, $e ;
# }
# Préparation avec marquage
$requete = "SELECT titre, auteur, genre FROM $table ";
$requete .= " WHERE titre like ? and genre = ?" ;
$sth = $dbh->prepare($requete);
# affectation ordonnée des marqueurs, puis exécution
$sth->bind_param(1,'%mis%');
$sth->bind_param(2,'roman');
$nb = $sth->execute();
# récupération des romans dont le titre contient "mis"
while ( @ligne = $sth -> fetchrow_array) {
print "@ligne\n" ;
$req="INSERT INTO inscrits (nom, prenom, classe) VALUES('toto','jules','5A');
$dbh -> do($req);
$req= "select count(*) from $table"; @enr = $dbh -> selectrow_array($req); print "@enr\n";
$sth = $dbh->prepare("SELECT titre, auteur, editeur FROM documents");
$sth->execute();
$sth->dump_results;
$nbChamps = $sth->{'NUM_OF_FIELDS'};
print "Nombre de champs = $nbChamps\n";
# service mysql status # ps aux | grep mysql
# mysql
mysql>SET PASSWORD FOR root= PASSWORD('fctice');
mysql>create database cdi mysql> quit # mysql -u root -p cdi < cdi.sql # mysql -u root -p cdi mysql>show tables; ....
mysql> GRANT select,insert,update,delete ON cdi.* TO admin@localhost IDENTIFIED BY "admin";
$ mysql -u admin -p --- donner le mot de passe : admin --- mysql> use cdi mysql> describe documents; mysql> select * from inscrits; mysql> quit $
#!/usr/bin/perl -w
# cdi1.pl, compter les enregistrements des tables
# définir quelques variables :
$dsn =
$login = "admin";
$mdp = "admin";
%tables=('1'=>'documents','2'=>'inscrits','3'=>'demandes','4'=>'prets');
# charger le module DBI
# connexion de admin à la base cdi ou affichage d'un message de sortie
$dbh =
# afficher la liste des tables, à partir du hachage %tables, sous la forme :
# 1 --> documents
# 2 --> inscrits
print "Liste des tables :\n";
foreach ...
print ...;
# saisie d'un numéro
print "Choisir une table :\n";
print "numéro = ";
$num=<>;
.....
# attention, vérifier l'existence de la clé dans le hachage
$table= .... if ...
# écriture de la requête sous forme de chaine
$requete = "SELECT count(*) FROM $table";
# préparer, exécuter
.........
# extraire l'unique valeur du champ, donc pas besoin de boucle ..
.........
# affichage du résultat
print "Il y a .... enregistrements dans la table $table\n";
# écriture de ce qui précéde en UNE ligne avec selectrow_array
print "En une ligne, je trouve ", .... ," enregistrements !\n";
#!/usr/bin/perl -w
# cdi2.pl, extractions de la base CDI
# meme début que cdi1.pl
$table = "inscrits";
$requete= "SELECT * FROM $table WHERE .................";
$sth = $dbh->prepare($requete);
# lire la classe
...............
# lire une partie du nom
# effectuer les liaisons
$sth->bind_param( ......);
$sth->execute();
$nbchamps = $sth->{'NUM_OF_FIELDS'};
print "Nb de champs = $nbchamps\n";
while (..............) {
print "...........\n";
}
Prolongement (cdi2bis.pl)
---------------------------------------------------------------------
#! /usr/bin/perl -w
# Connexion simultanée à 2 BD, l'une sous PostgreSQL, l'autre sous MySQL.
###############################
use DBI;
# Réalise la connexion en utilisant le pilote Pg pour PostgreSQL
$dbhpg = DBI->connect("dbi:Pg:dbname=cdi","","")
or die "Impossible de se connecter à la base PostgreSQL : $DBI::errstr\n";
$dbhmy = DBI->connect("dbi:mysql:cdi","admin","admin")
or die "Impossible de se connecter à la base mSQL : $DBI::errstr\n";
$dsn = "DBI:mysql:database=$database;host=$hostname;port=$port"; $dbh = DBI->connect($dsn, $user, $password) or die "echec de la connexion !\n";
$sth -> quote($value);
$descripteur_ligne = $dbh -> do($requete, @bind_values);
@row = $dbh ->selectrow_array($requete, @bind_values);
| Méthodes de la classe DBI | Description |
use DBI; | inclure le module d'accès aux BD |
$dsn ="DBI:mysql:$bd:[$hote:$port]";
| Définir une source de données (par défaut $hote = localhost et (pour mysql) $port=3306) |
$dbh=DBI->connect($dsn,$login,$mdp); | tente la connexion
au serveur et à la base spécifiée (ici avec chargement dynamique du pilote DBD::mysql). En cas de succès, retourne un descripteur de connexion à la base (mysql) En cas d'échec, retourne undef (interprété comme faux) et renseigne $DBI::err et $DBI::errstr. |
$sth->finish ; | termine le traitement et libère les ressources déconnexion du serveur |
$sth=$dbh->prepare($requete); | prépare la requête avant exécution (recommandé), et renvoie un descripteur de traitement |
$cr=$sth->execute([@valeurs]); | exécute la requête préparée, avec passage des éventuelles
valeurs des paramètres liés (dans l'ordre des positions indiquées par ? dans la requête) et retourne un
compte-rendu entier (utilisable comme booléen) Pour les requêtes non SELECT, retourne le nombre de lignes affectées ou "0E0" s'il n'y en a pas, ce que PERL interpréte comme 0 (faux) |
$cr=$dbh->do($requete[, @valeurs]); | prépare et exécute la requête SQL, de façon plus rapide, s'il n'y a pas de paramètres (l'éventuelle liste @valeurs des valeurs liées doit correspondre aux marqueurs ?). |
$dbh->quote($requete); | pour résoudre les pbs des apostrophes dans les chaines de requête à insérer, plus généralement protège les caractères spéciaux SQL par des \ |
@liste=$sth->fetchrow_array; | Extrait la ligne de données suivante et la
retourne sous forme d'un tableau indicé contenant les valeurs des champs (ou undef dans le cas de valeurs
NULL). Quand le parcours est fini, la liste retournée est vide et l'affectation est évaluée à FALSE, en contexte booléen (dans une condition while) |
@ligne=$dbh->selectrow_array($requete[,@valeurs]); | Combine préparation, exécution de la requête passé directement à la base. |
$ligne=$sth->fetchrow_arrayref; | Recherche la ligne de données suivante et la retourne sous forme d'une référence vers une liste de champs (ou undef). |
fetchall_arrayref; | recherche toutes les données et les stockent dans une référence vers une liste de listes. |
$sth->bind_param(1,val1); $sth->bind_param(2,val2); ..... $sth->execute();
# Connexion à la base de données avec activation des transactions et de la gestion des erreurs
$dbh = DBI->connect( "dbi:mysql:$bd" , { AutoCommit => 0,RaiseError => 1 } );
# ou pour désactiver l'autocommit # $dbh -> {AutoCommit}=0 ;
.. modifications sur la base ..
# si tout le traitement est validé, on "commet" les modifications
$dbh -> commit or die $sth->errstr ;
# sinon, on annule les modifications faites avant l'erreur
$dbh->rollback();
Mysql ne supporte pas les transactions (contrairement à Postgresql, et au pilote DBD::Pg). Pour Mysql, l'attribut
AutoCommit d'un descripteur de bd ($dbh) est donc implictement toujours 1
$dbh = DBI->connect($dsn, $login, $mdp) or die "Echec de la connexion\n";
$table = "documents";
$requete = "SELECT titre, auteur, editeur FROM $table ";
$sth = $dbh->prepare($requete);
$sth->execute();
print "Titre\t Auteur\t Editeur \n";
# syntaxe usuelle
while ( @ligne = $sth -> fetchrow_array) {
print "@ligne[0] @ligne[1] @ligne[2]\n" ;
}
# variante plus explicite
while ( ($t, $a, $e) = $sth -> fetchrow_array) {
print "$t $a $e\n" ;
}
# avec référence liste
while ( $ref = $sth -> fetchrow_arrayref) {
print "$ref->[0] $ref->[1] $ref->[2]\n" ;
}
# avec référence hachage
while ( $ref = $sth -> fetchrow_hashref) {
print "$ref->[titre] $ref->[auteur] $ref->[editeur]\n" ;
}
$sth->fetchall_arrayref permet de récupérer d'un coup les références vers le jeu de résultats de la requete : la
valeur scalaire renvoyée est une référence vers un tableau de référence de chaque ligne de résultat
# donc pas besoin de boucle, $ref pointe vers une structure englobant toutes les données du résultat
$ref = $sth -> fetchall_arrayref;
# une boucle pour récupérer chaque référence vers un tableau
foreach $r (@$ref) {
print "$r->[0] $r->[1] $r->[2] $r->[3]\n" ;
}