Mòdul 7   

Pràctica 8: Connectant MySQL amb Java
Tornar presentació tema
      Prąctica 1 Pràctica 2 Prąctica 3 Pràctica 4 Pràctica 5 Pràctica 6 Pràctica 7 Prąctica 8 Pràctica 9 Pràctica 10
 

El motor de dades MySQL i el llenguatge Java treballen força bé junts. En aquesta pràctica aprendràs a accedir a la informació enregistrada a les taules MySQL a través dels components de bases de dades de Java.

Els creadors de Java es van asegurar de fer un disseny fàcil i polivalent d'accés a dades. Van crear un conjunt d'interfícies que cada fabricant ha implementat per a connectar Java amb el seu servidor de dades: una interfície serveix per a connectar amb els motors de dades, una altra la utilitzaràs per a fer preguntes al servidor, una tercera per a recollir les respostes... D'aquesta forma la programació dels accesos a les dades es torna independent del motor de dades: si el programador sap fer una consulta al MySQL, també la sap fer a l'Oracle o a l'Interbase perquè la sintaxi és idèntica.

Aquestes implementacions de les interfícies Java de bases de dades es distribueixen en forma de llibreries .jar i es coneixen amb el nom de 'drivers JDBC'. Per a utilitzar-les, habitualment només et caldrà deixar la llibreria JDBC de la base de dades que vols connectar en un lloc on la màquina virtual de Java la pugui trobar.

En aquesta pràctica

  • aprendràs a instal·lar un driver JDBC a la carpeta de llibreries del Resin,
  • faràs una classe genèrica de gestió de les connexions que utilitzaràs en el portal de notícies ACME
  • aprendràs a utilitzar les classes de connexió a dades
  • representaràs dades del MySQL en una pàgina web.


 
  Instal·lar el Connector MySQL de Java.  
 


Els connectors JDBC fan la tasca d'intermediaris entre les classes de Java i els servidors de dades. El programador escriu sentències SQL que el connector s'encarrega d'enviar al motor de dades. Quan aquest contesta, el connector en recull la resposta i la serveix al programador.

Per a gairebé tots els motors de dades importants existeix un o més connectors JDBC per a què Java pugui interactuar amb les bases de dades. Aquí et proposem treballar amb el connector de l'empresa propietària del MySQL. Pots baixar-te'l des de la web de MySQL o, si ho vols més senzill, pots recollir el driver des d'aquí (no oblidis descomprimir-lo abans d'utilitzar-lo)

A efectes d'instal·lació el procés és bàsic: només has de posar la llibreria del connector, que és un sol fitxer, a l'abast del Resin.

Després retocaràs la configuració del servidor web per a què sigui el propi Resin qui s'encarregui de gestionar les connexions amb la base de dades i ens estalvii una mica de feina de programació.

Has de seguir els següents dos passos:

1) Deixar el connector JDBC a la carpeta /lib del Resin: Descarrega't el connector mysql-connector-java-3.0.16-ga-bin.jar i deixa'l a la carpeta c:/java/resin-3.0.9/lib.

2) Explicar-li al Resin com es diu i on està la base de dades agencia_noticies. Obre el fitxer de configuració del Resin a c:/java/resin-3.0.9/conf/resin.conf amb la llibreta del windows. A l'espai entre aquesta etiqueta

</web-app-default>

i aquesta

<!--
- Default host configuration applied to all virtual hosts.
-->
<host-default>

Escriu el següent fragment de text:

 

<database>
<jndi-name>jdbc/mysqlacme</jndi-name>
<driver type="org.gjt.mm.mysql.Driver">
<url>jdbc:mysql://localhost:3306/agencia_noticies</url>
<user>root</user>
<password>root</password>
</driver>
<prepared-statement-cache-size>8</prepared-statement-cache-size>
<max-connections>20</max-connections>
<max-idle-time>30s</max-idle-time>
</database>

 
 


Amb això li indiques al servidor web que utilitzi la base de dades MySQL agencia_noticies i que la reconegui amb el nom jdbc/mysqlacme. Que aquesta base de dades està en local (localhost) i surt pel port 3306. Que ens connectarem com a usuari root que té com a contrassenya root. Finalment li dones el límit de connexions que ha de permetre el driver (màxim de 20 connexions a la vegada) . Si obres la web a internet, pots ampliar el número de connexions màximes.

Enregistra el fitxer resin.conf.

Això és tot. Ja tens tot a punt per a escriure programes de Java que es connectin al MySQL.

 

 
  Una utilitat per a gestionar les connexions amb el MySQL  
 


Abans d'escriure la primera pàgina web que connecta amb la base de dades et proposem que escriguis una classe auxiliar que utilitzaràs en tot el projecte per a fer-te més fàcil la tasca de programació de la base de dades. No pateixis massa si no l'entens completament, d'aquí a finals del mòdul la sabràs interpretar correctament.

 

Obre el projecte 'classes' del BlueJ (c:/java/resin-3.0.9/webapps/noticiesacme/WEB-INF/classes).

Fes doble clic sobre el paquet util. Escriu la següent classe amb el nom DAOUtils.java. Insistim, no et preocupis massa si d'entrada no entens el significat del codi:

 
package acme.util;

import java.sql.*;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.*;

/**
*
* @author Angel Solans
* Utilitat d'accés a la base de dades.
* Obté, obre i tanca connexions, statements i resultsets des del pool
* de connexions de Resin
*/

public class DAOUtils {

private DAOUtils() { } // La classe no es pot instanciar


public static Connection getDBConnection()
  throws SQLException {
    Connection conn = null;
    try {
        Context env = (Context) new             InitialContext().lookup("java:comp/env");
        DataSource ds = (DataSource) env.lookup("jdbc/mysqlacme");
        conn = ds.getConnection();
    } catch (NamingException e) {
        e.printStackTrace();
    }
    return conn;
}

public static void closeConnection(Connection dbConnection)
  throws SQLException {
    if (dbConnection != null && !dbConnection.isClosed()) {
        dbConnection.close();
    }
}

public static void closeResultSet(ResultSet result)
  throws SQLException {
    if (result != null) {
        result.close();
    }
}

public static void closeStatement(PreparedStatement stmt)
  throws SQLException {
    if (stmt != null) {
        stmt.close();
    }
}
}

 
 


Com ja t'hem dit, aquesta classe t'ha de servir per a fer més senzill el rutinari procés de connectar-te, desconnectar-te i consultar a la base de dades.

Compila el programa per a verificar que no hi ha errors.

Ara revisaràs el codi d'aquesta classe DAOUtils i així aprofitarem per a presentar-te les classes que ens facilita Java per a treballar amb bases de dades.

 

 
  Classes de Java per a connectar amb bases de dades: Connection, PreparedStatement i ResultSet.  
 

 

Si llegeixes DAOUtil.java observaràs que s'hi utilitzen algunes classes que et són completament desconegudes. Mira si trobes les classes Connection, PreparedStatement i ResultSet. Ens interessa que et concentris en aquestes tres classes perquè són el nucli de la connectivitat de Java amb una base de dades.

Si penses en abstracte en què necessites per a treballar amb dades descobriràs el sentit d'aquestes tres classes: necessites connectar-te amb el servidor de dades, necessites llançar-li preguntes i necessites obtenir-ne respostes.

Com sempre en Java, has de pensar la gestió de dades en termes d'objectes:

-He de connectar-me a una base de dades, a través de què ho faig?
-A través d'un objecte Connection.

-Ara ja m'he connectat, com li envio una petició al servidor de dades?
-A través d'un objecte PreparedStatement. que et prestarà l'objecte Connection

-Ja he fet la petició de dades al servidor de dades. com recullo la resposta que m'envia?
- A través d'un objecte ResultSet. que et prestarà l'objecte Connection

Així doncs

  • els objectes java.sql.Connection serveixen per a obrir un canal de comunicació entre el programa de Java i el MySQL. Fan circular les consultes que fem al motor de dades i retorna les respostes del servidor. La seva funció és la de carretera per on circula la informació.
  • els objectes java.sql.PreparedStatement són les preguntes que fem al servidor en llenguatge SQL.
  • els objectes java.sql.ResultSet són les respostes que ens retorna el servidor. Com la respostes en llenguatge SQL són, de fet, taules de dades, els objectes ResultSet contenen al seu interior una taula de dades.

 

 
 

Per a entendre millor el funcionament, ara posaràs a treballar aquestes tres classes:

 

 
  Una pàgina web que llista els autors del portal de notícies ACME: Plain Old Java Objects i consultes  
 

 

Et proposem que escriguis una pàgina web que, en cridar-la, et faci una llista dels autors enregistrats en el teu portal.

Necessitaràs fer:

  1. Crear una classe que representi els objectes Autor.
  2. Escriure una consulta a la base de dades que ens ha de retornar la llista d'autors de la base de dades
  3. Escriure una pàgina web que imprimeixi la llista d'autors.

1) La classe Autor.java.
A la pràctica 4 del mòdul 4 et parlàvem dels POJO (Plain Old Java Objects). Recorda que són classes de Java que només descriuen la forma d'un objecte. Contenen només constructor/s, camps privats i mètodes accessors als camps ( getters i setters ).

Els objectes gestionats pel teu portal (articles, autors, visites...) tindran tots forma de POJO. Has de pensar cadascuna d'aquestes classes com una representació en Java de l'estructura d'una taula MySQL. Si tens una taula d'articles, faràs una classe que es digui Article. Si tens una taula d'autors, faràs una classe que es digui Autor. Si tens una taula que es diu visites faràs un objecte que es digui Visita.

D'aquesta forma pots, per exemple, encabir la informació d'un registre de la taula d'autors en un objecte de Java Autor. I pots posar tota la informació d'una taula o consulta d'Autors en un vector o una matriu d'objectes Autor:


 
   
 
Equivalència entre una taula d'Autors el l'objecte de Java Autor.
 
1) Obre el BlueJ i crea aquesta classe Autor.java dins el paquet acme:

 
package acme;

/**
* @author Angel Solans
* @version 15-12-2004
*/

public class Autor {
    private String nick;
    private String nom;
    private String cognom1;
    private String cognom2;
    private String clau;
    private boolean actiu;

    public Autor() {
    }

    public String getClau() {
        return clau;
    }
    public void setClau(String clau) {
        this.clau = clau;
    }
    public String getCognom1() {
        return cognom1;
    }
    public void setCognom1(String cognom1) {
        this.cognom1 = cognom1;
    }
    public String getCognom2() {
        return cognom2;
    }
    public void setCognom2(String cognom2) {
        this.cognom2 = cognom2;
    }
    public String getNick() {
        return nick;
    }
    public void setNick(String nick) {
        this.nick = nick;
    }
    public String getNom() {
        return nom;
    }
    public void setNom(String nom) {
        this.nom = nom;
    }
    public boolean isActiu() {
        return actiu;
    }
    public void setActiu(boolean actiu) {
        this.actiu = actiu;
    }

}

 
 


Observa que es tracta d'una classe plana, que només descriu unes dades, que aquestes dades es corresponen als camps de la taula MySQL "autors" i que els camps són privats i es publiquen a través dels getter i setter corresponents.

Assegura't que el codi està ben escrit compil·lant la classe.

 

2) Ara faràs una consulta a la base de dades. Atenció amb el contingut d'aquesta classe! Es fonamental que intentis entendre el seu funcionament.

Dins el paquet util crea una nova classe que es digui Consultes.java. En aquesta classe aniràs desaant totes les consultes que fas a la base de dades. Posteriorment, quan necessitis obtenir informació del MySQL només et caldrà instanciar la classe Consultes i cridar el mètode corresponent.

Ha de tenir el següent contingut:

 
package acme.util;

import acme.*;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import java.util.*;

/**
* @author Angel Solans
* @version 15-12-2004
*/

public class Consultes {
    /**
    * Retorna una matriu d'objectes autor amb tots els autors
    * de la base de dades
    */
    public Autor[] getAutors() throws SQLException {
        Autor[] autors = null;
        Autor autor = null;
        Vector v = new Vector();
        Connection connexio = DAOUtils.getDBConnection();
        PreparedStatement stmt = connexio.prepareStatement("SELECT *             FROM AUTORS ORDER BY COGNOM1,COGNOM2,NOM");
        ResultSet rs = stmt.executeQuery();
        while (rs.next()) {
            autor = new Autor();
            autor.setNick(rs.getString("AUTOR"));
            autor.setNom(rs.getString("NOM"));
            autor.setCognom1(rs.getString("COGNOM1"));
            autor.setCognom2(rs.getString("COGNOM2"));
            autor.setActiu(rs.getInt("ACTIU")==1);
            v.add(autor);
        }
        rs.close();
        stmt.close();
        connexio.close();

        autors = new Autor[v.size()];
        for (int n=0;n<autors.length;n++) {
            autors[n]=(Autor)v.get(n);
        }
    
        return autors;
    }

}

 
 


De moment la classe només conté un mètode, getAutors(), amb el següent funcionament:

  • El mètode està protegit amb una excepció, concretament una SQLException:

              public Autor[] getAutors() throws SQLException {

    Quan un programa de Java es connecta a una base de dades i alguna cosa no funciona bé (el servidor de dades està aturat, has escrit el codi SQL amb error ...) retorna una excepció SQLException. Sempre que utilitzis objectes Connection, PreparedStatement, ResultSet protegeix el programa amb una SQLException.

  • Et connectes a la base de dades a través d'un connexió que ens cedeix la classe recent creada DAOUtils.java.

            Connection connexio = DAOUtils.getDBConnection();

    Si tot ha funcionant bé, després d'aquesta sentència l'objecte connexio representa una connexió amb el MySQL. Ara tens el servidor de dades escoltant les teves demandes.
  • Amb la connexió oberta, fas una pregunta al motor de dades:

    PreparedStatement stmt = connexio.prepareStatement("SELECT *  FROM AUTORS ORDER BY COGNOM1,COGNOM2,NOM");

    Crees un objecte PreparedStatement a partir de la connexió i el seu mètode prepareStatement(). Com a paràmetre li passes la sentència SQL amb la pregunta que li fas al servidor MySQL. En aquest cas li demanes tots els registres de la taula autors ordenats per cognom i nom.
  • Envies la pregunta al servidor i en reps la resposta, tot a la vegada, amb aquesta sentència:

            ResultSet rs = stmt.executeQuery();

    L'objecte ResultSet conté la taula amb les dades de la resposta del MySQL.
  • Ara navegues per l'objecte ResultSet per anar carregant les dades dels autors en un vector d'Autors:

         while (rs.next()) {
             autor = new Autor();
             autor.setNick(rs.getString("AUTOR"));
             autor.setNom(rs.getString("NOM"));
             autor.setCognom1(rs.getString("COGNOM1"));
             autor.setCognom2(rs.getString("COGNOM2"));
             autor.setActiu(rs.getInt("ACTIU")==1);
             v.add(autor);
         }



    Amb rs.next(), vas saltant per cada registre del ResultSet. A cada pas, crees un objecte autor i n'omples cada camp amb el camp equivalent de la taula MySQL (recorda l'equivalència POJO-Taula MySQL).
    Com el camp actiu de la classe autor és boolean i el MySQL no treball directament amb camps lògics, en fas una traducció: l'autor és actiu si el camp actiu a la taula MySQL és igual a 1. En cas contrari no és actiu.
  • Un cop has carregat les dades, tanques el ResultSet, el PreparedStatement i la Connection.

            rs.close();
            stmt.close();
            connexio.close();

    Sempre has de tancar explícitament aquests objectes, per no mantenir oberts canals de comunicació amb el motor de dades que ja no utilitzes i així estalviar recursos del servidor.
  • Finalment, tradueixes les dades del vector a la matriu d'Autors i en retornes el contingut.

            autors = new Autor[v.size()];
            for (int n=0;n<autors.length;n++) {
                autors[n]=(Autor)v.get(n);
            }
        
            return autors;
 
     
 

3) La última peça del puzzle és la pàgina web.

Ara escriuràs la pàgina web autors.jsp que deixaràs a la carpeta arrel del projecte, c:/java/resin-3.0.9/webapps/noticiesacme:

 
<%@ page language="java" import ="acme.*,acme.util.*"%>
<%
    Consultes consultes = new Consultes();
    Autor[] autors = consultes.getAutors();
%>


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Autors del Portal</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>

<body>
<h3>Llista d'Autors del Portal ACME</h3>
<hr>
<p>
<ul>
<% if (autors!=null) for (int n=0;n<autors.length;n++) { %>
    <li><%=autors[n].getNom()%> <%=autors[n].getCognom1()%>         <%=autors[n].getCognom2()%></li>
<% } %>

</ul>
</p>
</body>
</html>

 
 


Observa els elements de codi destacats amb negreta:

  • Fas una importació de les classes que utilitzaràs a la pàgina:
        import ="acme.*,acme.util.*"
  • Crees una instància del contenidor de consultes a la base de dades:

        Consultes consultes = new Consultes();
  • Carregues el resultat de la consulta en una matriu d'autors:

        Autor[] autors = consultes.getAutors();
  • Finalment, imprimeixes recursivament el resultat a la pàgina web:

        <% if (autors!=null) for (int n=0;n<autors.length;n++) { %>
            <li><%=autors[n].getNom()%> <%=autors[n].getCognom1()%>             <%=autors[n].getCognom2()%></li>
        <% } %>


 
 

Activa el Resin i crida la següent pàgina:http://localhost/autors.jsp . Has d'obtenir el següent resultat.

 

 
   
 



Recorda que,

Has de crear una classe de Java per a cada 'objecte' (articles, autors, seccions ...) que necessitis en el teu programa. Aquesta classe ha de 'descriure' la taula corresponent a la base de dades, amb camps privats i mètodes getter i setter públics.

Acumula les consultes que has de fer a la base de dades en una única classe (Consultes.java). Ves afegint mètodes en funció de les necessitats del programa. Si es tracta de mètodes que obtenen informació, fes que el seu nom comenci per get (getAutors(), getArticles(), getSeccions()). Si es tracta de mètodes que enregistren informació escriu el seu nom començant per add (addAutor(), addArticle(), addSeccio()...)

 
     

1) Analitza perquè al mètode getAutors() utilitzem un Vector com a intermediari entre el ResultSet i la matriu d'autors. Perquè no utilitzem directament una matriu en lloc del Vector?

2) Escriu un resum en paper descrivint el contingut d'aquest esquema:

 
 
 
 
Model de Connexions amb el MySQL del teu projecte
 
     
 

 

Tornar al principi