Documentation PostgreSQL 7.4.29 | ||||
---|---|---|---|---|
Précédent | Arrière rapide | Chapitre 31. Interface JDBC | Avance rapide | Suivant |
PostgreSQL fournit deux façons distinctes de stocker des données binaires. Elles peuvent être stockées dans une table en utilisant le type de données bytea ou en utilisant la fonctionnalité des gros objets qui stockent les données binaires dans une table séparée dans un format spécial et se réfère à cette table en stockant une valeur de type oid dans votre table.
Pour déterminer quelle méthode est appropriée, vous avez besoin de comprendre les limitations de chaque méthode. Le type de données bytea ne convient pas bien pour stocker de grosses quantités de données binaires. Alors qu'une colonne de type bytea peut contenir jusqu'à 1 Go de données binaires, elle demanderait une énorme quantité de mémoire pour traiter une telle valeur. La méthode des objets larges convient mieux pour stocker de très grands objets mais a ses propres limitations. Spécifiquement, supprimer une ligne contenant une référence de gros objet ne supprime pas le gros objet. Supprimer celui-ci est une opération qui doit être réalisée séparément. Les gros objets ont aussi quelques problèmes de sécurité car toute personne connectée à la base de données peut visualiser et/modifier tout gros objet même s'il n'a pas le droit de visualiser/mettre à jour la ligne contenant la référence au gros objet.
La version 7.2 a été la première à disposer d'un pilote
JDBC supportant le type de données bytea.
L'introduction de cette fonctionnalité dans la 7.2 a introduit une
changement dans le comportement comparé aux précédentes versions. Depuis la
7.2, les méthodes getBytes()
,
setBytes()
, getBinaryStream()
et
setBinaryStream()
opèrent sur le type de données
bytea. En 7.1 et pour les versions précédentes, ces méthodes
opéraient sur le type de données oid associé avec chaque gros
objet. Il est possible de revenir à l'ancien comportement de la version 7.1
en initialisant la propriété compatible de l'objet
Connection
avec la valeur 7.1.
Pour utiliser le type de données bytea, vous devez simplement
utiliser les méthodes getBytes()
,
setBytes()
,
getBinaryStream()
ou
setBinaryStream()
.
Pour utiliser la fonctionnalité des gros objets, vous devez utiliser soit
la classe LargeObject
fournie par le pilote
JDBC de PostgreSQL soit
utiliser les méthodes getBLOB()
et
setBLOB()
.
Important : Vous devez accéder aux gros objets à l'intérieur d'un bloc de transaction SQL. Vous pouvez lancer un bloc de transaction en appelant
setAutoCommit(false)
.
Note : Dans une prochaine version du pilote JDBC driver, les méthodes
getBLOB()
etsetBLOB()
n'interagiront plus avec les gros objets mais fonctionneront avec le type de données bytea. Donc, il vous est recommandé d'utiliser l'API deLargeObject
si vous pensez utiliser des gros objets.
Exemple 31-8 contient quelques exemples sur le traitement de données binaires en utilisant le pilote JDBC de PostgreSQL.
Exemple 31-8. Traiter des données binaires avec JDBC
Par exemple, supposez que vous avez une table contenant des noms de fichiers d'images et que vous souhaitez aussi stocker l'image dans une colonne de type bytea :
CREATE TABLE images (nomimg text, img bytea);
Pour insérer une image, vous utiliserez :
File file = new File("monimage.gif"); FileInputStream fis = new FileInputStream(file); PreparedStatement ps = conn.prepareStatement("INSERT INTO images VALUES (?, ?)"); ps.setString(1, file.getName()); ps.setBinaryStream(2, fis, file.length()); ps.executeUpdate(); ps.close(); fis.close();
Ici, setBinaryStream()
transfère un certain nombre
d'octets d'un flux dans la colonne de type bytea. Ceci
pourrait aussi être fait en utilisant la méthode
setBytes()
si le contenu de l'image était déjà dans un
byte[]
.
Récupérer une image est encore plus simple. (Nous utilisons
PreparedStatement
, mais la classe
Statement
pourrait très bien la remplacer.)
PreparedStatement ps = con.prepareStatement("SELECT img FROM images WHERE nomimg = ?"); ps.setString(1, "monimage.gif"); ResultSet rs = ps.executeQuery(); if (rs != NULL) { while (rs.next()) { byte[] imgBytes = rs.getBytes(1); // utiliser les données ici... } rs.close(); } ps.close();
Ici, les données binaires ont été récupérées dans un
byte[]
. À la place, vous pourriez avoir utilisé un
objet InputStream
.
Vous pouvez aussi stocker un très gros fichier et vouloir utiliser
l'API LargeObject
pour stocker le
fichier :
CREATE TABLE imageslo (nomimg text, oidimg oid);
Pour insérer une image, vous pourriez :
// Tous les appels à l'API LargeObject doivent se faire dans un bloc de // transaction conn.setAutoCommit(false); // Récupérer le gestionnaire des gros objets pour lui faire réaliser les // opérations LargeObjectManager lobj = ((org.postgresql.PGConnection)conn).getLargeObjectAPI(); // Créer un nouveau gros objet int oid = lobj.create(LargeObjectManager.READ | LargeObjectManager.WRITE); // Ouvrir le gros objet en écriture LargeObject obj = lobj.open(oid, LargeObjectManager.WRITE); // Maintenant, ouvrir le fichier File file = new File("monimage.gif"); FileInputStream fis = new FileInputStream(file); // Copier les données du fichier dans le gro objet byte buf[] = new byte[2048]; int s, tl = 0; while ((s = fis.read(buf, 0, 2048)) > 0) { obj.write(buf, 0, s); tl += s; } // Fermer le gros objet obj.close(); // Maintenant, insérer la ligne dans imageslo PreparedStatement ps = conn.prepareStatement("INSERT INTO imageslo VALUES (?, ?)"); ps.setString(1, file.getName()); ps.setInt(2, oid); ps.executeUpdate(); ps.close(); fis.close();
Pour récupérer l'image du gros objet :
// Tous les appels à l'API LargeObject doivent se faire dans un bloc de // transaction conn.setAutoCommit(false); // Récupérer le gestionnaire des gros objets pour lui faire réaliser les // opérations LargeObjectManager lobj = ((org.postgresql.PGConnection)conn).getLargeObjectAPI(); PreparedStatement ps = con.prepareStatement("SELECT oidimg FROM imageslo WHERE nomimg = ?"); ps.setString(1, "monimage.gif"); ResultSet rs = ps.executeQuery(); if (rs != NULL) { while (rs.next()) { // Ouvrir le gros objet en lecture int oid = rs.getInt(1); LargeObject obj = lobj.open(oid, LargeObjectManager.READ); // Lire les données byte buf[] = new byte[obj.size()]; obj.read(buf, 0, obj.size()); // Utiliser les données ici // Fermer l'objet obj.close(); } rs.close(); } ps.close();
Précédent | Sommaire | Suivant |
Créer et modifier les objets de la base de données | Niveau supérieur | Extensions PostgreSQL à l'API de JDBC |