Enrera
Mòdul 7
Iniciació a la programació en Java
  Pràctica
1
2
3
4
4
   
Exercicis
Exercicis
 
 
 

SQL i Java

   
  El model relacional de bases de dades:
   
SQL és el llenguatge de dades més universal. Es fonamenta en el model relacional de descripció de dades, una de les teories sobre emmagatzemament d'informació amb més seguidors. Els sistemes relacionals descriuen les dades en forma de taules bidimensionals organitzades en files i columnes. Les files són els registres o tuples i les columnes són els camps o atributs. Les taules han de tenir una clau primària, que identifiqui de manera única el registre a la taula (per exemple, el camp id de la taula usuaris a la base de dades biblioteca).. Cada taula es pot relacionar amb les altres a través de les claus externes: una taula conté informació d'una altra perquè emmagatzema la seva clau primària. Per exemple, la taula "llibres" pot contenir un camp que es digui "lector". En aquest camp no hi posaré totes les dades del lector, sinó la clau primària de la taula d'usuaris de la biblioteca:
   
 
Taula "Llibres":
Id Títol Autor Lector
1
Java 2
Froufe, Agustín 2
2 Java Bishop, Judy  
3 Piensa en Java Eckel, Bruce 3
 
Taula "Lectors":
Id Nom Cognom1 Cognom2
1 Josep Capdevila Peris
2 Anna Solans Mesalles
3 Marc Teulé Fitó
   
 

En aquest cas, el libre "Java 2" d'"Agustín Froufe" el té el lector "2" que és "Anna Solans Mesalles". Quan es va dissenyar el llenguatge SQL es buscava un llenguatge que fos entenedor per a usuaris poc experts en bases de dades. Havia de ser natural, amb una estructura similar a l'anglès escrit, que fes possible que l'usuari "preguntés" directament a la base de dades.

Per exemple, si necessitem saber saber el nom del lector del llibre d'"Agustín Froufe", SQL ho resol amb aquesta frase:

SELECT LECTOR.NOM FROM LECTORS,LLIBRES WHERE LECTORS.ID=LLIBRES.LECTOR AND LLIBRES.ID=1

és a dir: "retorna el camp nom des de la taula de lectors, tot considerant que:

  • el camp lector de la taula llibres és igual al camp id de la taula lectors i, a més,

  • el camp id de la taula de llibres és l'1"
Si heu de treballar amb bases de dades, és molt convenient que feu una repassada a algun text o curs de disseny de bases de dades relacionals. Podeu fer un cop d'ull al curs D50 o al curs D104. També us pot ser útil algun curs d'SQL dels que estan disponibles a Internet. Aquests en són bons exemples: de l'Aula Click i de la Universitat de Navarra.
   
  Sentències SQL de supervivència
   
  Donat que l'objectiu d'aquest curs no és pas l'estudi de les bases de dades us facilitem, només, algunes consultes SQL que fan les feines més importants de consulta i actualització sobre una base de dades. Veurem després com aplicar-les amb Java.
   
 
Sentències de consulta:
Objectiu: Sentència:
Obtenir tota la informació d'una sola taula: select * from lectors
Obtenir informació d'algunes columnes d'una taula select id,nom from lectors
Obtenir informació d'una taula posant alguna condició a un camp. Retorna els lectors que es diuen "Angel". select * from lectors where nom='Angel'
Obtenir informació d'una taula posant alguna condició no estricta a un camp. Retorna els lectors que es diuen "Angel", "Angela", "Angelines", etc. select * from lectors where nom like 'Angel%'
Obtenir informació d'una taula posant alguna condició no estricta a un camp. Retorna els lectors que es diuen "Angelina", "Martina", "Cristina", etc. select * from lectors where nom like '%ina'
Obtenir la suma de registres d'una taula select count(*) from lectors.
Obtenir la suma de registres d'una taula amb condicions select count(*) from lectors where nom='Angel'
Obtenir la llista dels noms i el nombre de vegades que apareixen a la taula de lectors select nom,count(*) from lectors group by nom
Obtenir la llista ordenada segons un camp d'una taula select * from lectors order by cognom1
Obté tots els camps d'una taula i alguns camps d'una altra. En aquest cas retorna tots els camps de la taula "llibres" i, per cada registre, el nom i cognoms dels lectors. Select llibres.*, lectors.id, lectors.cognom1, lectors.nom from lectors,llibres where lectors.id=llibres.lector
   
 
Sentencies d'actualització:
Objectiu: Sentència:
Afegir un camp insert into lectors (id,nom,cognom1,cognom2) values (7,"Miquel","Mesalles","Bernadó")
Esborrar tots els registres d'una taula delete from lectors
Esborrar condicionalment registres d'una taula delete from lectors where id=5
Esborrar els llibres el lectors dels quals es diuen 'Angel' delete from llibres where lector in (select id from lectors where nom='Angel')
Actualitzar un grup de registres. Atenció!, a SQL les consultes update poden afectar el mateix nombre de registres com posem a la nostra condició. Actualitza a 'ANGEL' tots els registres que tinguin de nom 'Angel' update lectors set nom='ANGEL' where nom='Angel'
Actualitza un registre passant com a condició la clau primària. update lectors set cognom1='Martí' where id=4
Actualitza més d'un camp a la vegada update lectors set soci='S', carnet='N' where id=25
   
  Un programa per a consultar, esborrar i actualitzar registres:
   

Ara escriurem un programa que ens permetrà experimentar amb diverses accions sobre una base de dades: afegir registres, esborrar-ne, actualitzar informació i llistar-la.

Escriviu, compileu i executeu el següent programa "GestioUsuaris.java":

   
 
import java.sql.*;
import java.io.*;

public class GestioUsuaris {

    public static void main (String[] args) throws IOException {
        String urlDades = "jdbc:odbc:biblioteca";
        String usuari = "";
        String clau = "";
        Connection connexio=null;
        Statement pregunta=null;
        ResultSet resposta=null;
        int opcio=-1;
        BufferedReader entrada=null;
            try {
                Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
            } catch (ClassNotFoundException e) {
                System.out.println(e.getMessage());
            }
            try {
                connexio=DriverManager.getConnection(urlDades,
                                                     usuari,
                                                     clau);
                System.out.println("Usuaris de la biblioteca");
                System.out.println("------------------------\n");
                    while (opcio!=0) {
                        entrada = new BufferedReader(
                        new InputStreamReader(System.in));
                        System.out.println(
                               "\n\nElegiu una tasca: 0 per sortir");
                        System.out.println("1- Insertar Usuari\n"+
                                           "2- Esborrar Usuari\n"+
                                           "3- Actualitzar Usuari\n"+
                                           "4- Llistar Usuaris\n\n");
                            try {
                                opcio = Integer.parseInt(
                                                 entrada.readLine());
                            } catch (Exception e) {
                                System.out.println(
                                         "Trieu un no. entre 0 i 4");
                                opcio=-1;
                            }
                            switch (opcio) {
                                case 1: AfegirUsuari afegir =
                                          new AfegirUsuari(connexio);
                                    break;
                                case 2: EsborrarUsuari esborrar =
                                        new EsborrarUsuari(connexio);
                                    break;
                            case 3: ActualitzarUsuari actualitzar =
                                     new ActualitzarUsuari(connexio);
                                    break;
                            case 4: LlistarUsuaris llista =
                                        new LlistarUsuaris(connexio);
                                    break;
                           }
                    }
            } catch (SQLException e) {
                System.out.println(e.getMessage());
            } finally {
                    try {
                        connexio.close();
                    } catch (SQLException e) {
                        System.out.println(e.getMessage());
                    }
            }
    }

}

class AfegirUsuari {

    Connection connexio=null;

    public AfegirUsuari (Connection connexio) throws IOException {
        this.connexio=connexio;
        inserta();
    }

    private void inserta() throws IOException {
        String text="";
        String nom="";
        String cognom1="";
        String cognom2="";

        BufferedReader entrada = new BufferedReader(
                                   new InputStreamReader(System.in));
        System.out.println("Nom de l'usuari, 0 per cancel.lar");
        text=(entrada.readLine());
            if (text.equals("0")) return; else nom=text;
                System.out.println("Primer cognom de l'usuari,"+
                                   " 0 per cancel.lar");
                text=(entrada.readLine());
                    if (text.equals("0")) {
                        return;
                    } else {
                        cognom1=text;
                    }
                System.out.println("Segon cognom de l'usuari, "+
                                   " 0 per cancel.lar");
                text=(entrada.readLine());
                    if (text.equals("0")) {
                        return;
                    } else {
                        cognom2=text;
                    }
                    try {
                        PreparedStatement pregunta =
                        connexio.prepareStatement("insert "+
                                                  "into usuaris "+
                                                  "(nom,cognom1,"+
                                                  "cognom2) "+
                                                  "values (?,?,?)");
                        pregunta.setString(1,nom);
                        pregunta.setString(2,cognom1);
                        pregunta.setString(3,cognom2);
                        pregunta.executeUpdate();
                        System.out.println("Insertat usuari "+
                                           nom+
                                           " "+
                                           cognom1+
                                           " "+
                                           cognom2);
                        pregunta.close();
                    } catch (SQLException e) {
                        System.out.println(e.getMessage());
                    }
     }

}

class EsborrarUsuari {

    Connection connexio;

    public EsborrarUsuari (Connection connexio) throws IOException {
        this.connexio=connexio;
        esborra();
    }

    private void esborra () throws IOException {
        PreparedStatement pregunta = null;
        BufferedReader entrada = new BufferedReader(
                                   new InputStreamReader(System.in));
        System.out.println("Introduiu el codi numeric de l'usuari");
        String usuari=entrada.readLine();
            try {
                pregunta=connexio.prepareStatement("delete "+
                                                   "from usuaris"+
                                                   "where id=?");
                pregunta.setString(1,usuari);
                pregunta.executeUpdate();
                System.out.println("Esborrat l'usuari "+usuari);
                pregunta.close();
           }catch(SQLException e) { }
     }
}

class ActualitzarUsuari {

    Connection connexio=null;

    public ActualitzarUsuari(Connection connexio) throws IOException {
        this.connexio=connexio;
        actualitza();
    }

    private void actualitza() throws IOException {
        BufferedReader entrada = new BufferedReader(
                                  new InputStreamReader(System.in));
        String text="";
        String usuari="";
        String nom="";
        String cognom1="";
        String cognom2="";
        System.out.println("Codi numeric de l'usuari");
        text=(entrada.readLine());
            if (text.equals("0")) {
                return;
            } else {
                usuari=text;
            }
        System.out.println("Nom de l'usuari, 0 per cancel.lar");
        text=(entrada.readLine());
            if (text.equals("0")) {
                return;
            } else {
                nom=text;
            }
        System.out.println("Primer cognom de l'usuari,"+
                           " 0 per cancel.lar");
        text=(entrada.readLine());
            if (text.equals("0")) {
                return;
            } else {
                cognom1=text;
            }
        System.out.println("Segon cognom de l'usuari,"+
                           " 0 per cancel.lar");
        text=(entrada.readLine());
            if (text.equals("0")) {
                return;
            } else {
                cognom2=text;
            }
            try {
                PreparedStatement pregunta =
                         connexio.prepareStatement("update usuaris"+
                                                   " set nom=?,"+
                                                   "cognom1=?,"+
                                                   "cognom2=? "+
                                                   "where id=?");
                pregunta.setString(1,nom);
                pregunta.setString(2,cognom1);
                pregunta.setString(3,cognom2);
                pregunta.setString(4,usuari);
                pregunta.executeUpdate();
                System.out.println("Actualitzat usuari "+
                                   nom+" "+
                                   cognom1+" "+
                                   cognom2);
                pregunta.close();
            }catch(SQLException e) {
                System.out.println(e.getMessage());}
            }

}

class LlistarUsuaris {

    Connection connexio=null;

    public LlistarUsuaris (Connection connexio) {
        this.connexio=connexio;
        llista();
    }

    private void llista() {
        Statement pregunta = null;
        ResultSet resposta = null;
            try {
                pregunta = connexio.createStatement();
                resposta = pregunta.executeQuery("select * from "+
                                                 "usuaris order "+
                                                 "by cognom1");
                System.out.println("\n\nLlista usuaris "+
                                   "de la biblioteca");
                System.out.println("----------------------------\n");
                    while (resposta.next()) {
                        System.out.println(
                                      resposta.getInt("id")+" "+
                                      resposta.getString("nom")+" "+
                                      resposta.getString("cognom1")+
                                      " "+
                                      resposta.getString("cognom2"));
                    }
                System.out.println("----------------------------\n");
                pregunta.close();
            } catch (SQLException e) {
            }
    }

}

   

Comentem una mica el funcionament del programa:

  • La classe principal del programa enregistra el drivers odbc:jdbc i connecta amb la base de dades. Seguidament entra en un cicle que presenta cinc opcions de menú. Una d'elles, el zero, provoca el tancament de la connexió amb les dades i la sortida del programa. Tot i que, en teoria, al tancar l'aplicació també es tanca la connexió, molts drivers no funcionen així i retenen els recursos de la connexió si no es tanca explícitament, fins i tot després de sortir del programa. Per tant, quan ja no necessitem una connexió, l'hem de tancar amb connexio.close(). El nostre programa funciona amb una connexió que s'obre a l'inici i es tanca al final. En aplicacions grans, amb molta concurrència (com ara una pàgina web), faríem anar un "pool" de connexions, una utilitat que mantindria sempre obertes vàries connexions i en serviria la primera que quedés lliure.

  • Un cop connectats amb la base de dades, triem alguna de les opcions del menú. Podem donar d'alta usuaris, esborrar-los de la base de dades, actualitzar-ne les dades i llistar-los. Cadascuna d'aquestes accions la fa una classe auxiliar. Quan necessitem alguna d'aquestes classes (EsborrarUsuari, AfegirUsuari, ActualitzarUsuari, LlistarUsuaris) la instanciem tot passant-li com a paràmetre la connexió que tenim activa.

  • Observeu les diferents estratègies a seguir segons el tipus de consulta

    • Obtenir dades sense paràmetres:

      Statement pregunta = connexio.createStatement();
      ResultSet resposta = pregunta.executeQuery(
                          "select * from usuaris order by cognom1");
          while (resposta.next()) {}

    • Esborrar dades passant paràmetres:

      PreparedStatement pregunta =
        connexio.prepareStatement("delete from usuaris where id=?");
      pregunta.setString(1,usuari);
      pregunta.executeUpdate();

    • Insertar dades passant paràmetres:

      PreparedStatement pregunta =
        connexio.prepareStatement(
        "insert into usuaris (nom,cognom1,cognom2) values (?,?,?)");
      pregunta.setString(1,nom);
      pregunta.setString(2,cognom1);
      pregunta.setString(3,cognom2);
      pregunta.executeUpdate();

    • Actualitzar dades passant paràmetres:

      PreparedStatement pregunta =
         connexio.prepareStatement(
         "update usuaris set nom=?,cognom1=?,cognom2=? where id=?");
      pregunta.setString(1,nom);
      pregunta.setString(2,cognom1);
      pregunta.setString(3,cognom2);
      pregunta.setString(4,usuari);
      pregunta.executeUpdate();

    • Observeu que, per a les consultes amb paràmetres, no utilitzem Statement sinó PreparedStatement. Els llocs de la consulta que han de ser substituïts pel paràmetre els indiquem amb el símbol '?'. Seguidament, per assignar el valor al paràmetre fem pregunta.setString(1,nom). Això substitueix el primer símbol '?' del la consulta SQL pel contingut de la variable nom. Si hem de passar un nombre enter hem d'escriure pregunta.setInt(1,numero).

    • Quan la consulta és d'actualització resolem Statement amb pregunta.executeUpdate() i, quan es tracta d'una consulta d'obtenció de dades fem pregunta.executeQuery().

  • Les preguntes, siguin Statement o PreparedStatement, també s'han de tancar explícitament després d'utilitzar-les, per tal d'alliberar recursos.
   
   
 
Amunt