Enrera
Mòdul 8
Iniciació a la programació en Java
  Pràctica
1
2
3
4
5
   
Exercicis
Exercicis
 
  Accés a bases de dades des de les pàgines web
   
 

La part més útil de la programació JSP és la possibilitat de sumar la utilització de Java, JDBC i JSP per presentar a un navegador i a qualsevol lloc del món, les dades que contenen les nostres bases de dades.

El disseny d'eines d'accés i manipulació de dades està, a hores d'ara, força automatitzat. Els programadors professionals disposen d'eines de pagament que els ajuden en el desenvolupament de les aplicacions amb accés a dades. Forte i JBuilder, en les seves versions professionals, disposen de components prefabricats d'accés i gestió de dades. Fins i tot Dreamweaver de Macromedia ens pot facilitar bastant la feina si treballem amb el motor Microsoft Access.

També les especificacions JSP ens faran servei i ens facilitaran la programació de gestió de dades, a través de les Llibreries d'Etiquetes personalitzades. Gràcies a marcadors a l'estil de HTML, podem activar connexions, presentar taules, etc.

A partir d'aquesta pràctica recuperarem el que vàrem treballar a les pràctiques 4 i 5 del mòdul anterior per tal de fer-ho servir en aquest entorn d'aplicacions web.

En aquesta primera aproximació utilitzarem una metodologia poc neta, que desaconsellem per a les vostres aplicacions JSP: totes les passes del procés d'accés, consulta i actualització de dades les trobareu a la pròpia pàgina JSP en forma de scriptlet. Per fer un repàs dels conceptes necessaris pel maneig de bases de dades amb Java aquest enfocament és suficient, però. Ara bé, si projecteu escriure algun programa real, és aconsellable que utilitzeu la metodologia dels Java Beans que estudiarem a la pràctica 4.

 
Una pàgina web de java amb accés a dades
   
  Crearem la pàgina HTML usuaris.jsp, la qual ens retornarà la llista de tots els usuaris que tenen carnet a la nostra biblioteca virtual. Amb el processador de textos, Dreamweaver o equivalent creem un fitxer usuaris.jsp, que deixarem al directori c:/biblioteca.

La pàgina recollirà les dades de la taula "usuaris" que és a la base de dades llibres.mdb. Si obriu la taula amb Access, veureu que està formada per quatre camps: id, cognom1, cognom2 i nom.
   
  <%@ page import="java.sql.*"%>

<html>

<head>
<title>Usuaris de la biblioteca</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>

<body bgcolor="#FFFFFF" text="#000000">
  <p>
    <font face="Arial, Helvetica, sans-serif" size="2">
      <b>LLISTA D'USUARIS ENREGISTRATS AL SERVEI DE BIBLIOTECA DE
      L'INSTITUT</b>
    </font>
  </p>
  <p>
<%

String nomsencerusuari="";
int comptador = 0;

String Urldades = "jdbc:odbc:biblioteca";
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection connexio = DriverManager.getConnection(Urldades,"","");
Statement pregunta = connexio.createStatement();
ResultSet resposta = pregunta.executeQuery("select * from usuaris "+
                                           "order by cognom1");
    while (resposta.next()) {
        nomsencerusuari = resposta.getString("cognom1")+" "+
                          resposta.getString("cognom2")+","+
                          resposta.getString("nom");
        comptador++;
%><%=nomsencerusuari%><br><%
    }
pregunta.close();
connexio.close();
%>
</p>
Actualment la biblioteca compta amb <%=comptador%> lectors/es
</body>
</html>

   
  Posem en marxa el programa servidor Resin, piquem sobre la primera opció de menú de http://localhost, http://localhost/usuaris.jsp. Si ho tenim tot bé: font ODBC, base de dades i pàgina HTML, obtindrem el següent resultat:

Estudiem una mica en detall què hem fet:

  • Utilitzem la directiva d'importació del paquet java.sql.*. És el paquet que conté les classes Connection, Statement, ResultSet per a la gestió de bases de dades.

  • Al scriptlet principal, hi declarem una variable que contindrà els noms dels usuaris de la biblioteca "nomsencerusuari" i un enter, "comptador", que anirà fent el recompte dels usuaris.

  • Introduïm la seqüència de connexió amb les dades, registrant el driver JDBC i obtenint la connexió.

  • Un cop tenim la connexió, llancem la pregunta Statement i obtenim la resposta ResultSet.

  • L'objecte ResultSet conté una matriu de dades, amb un registre per a cada registre de la taula que Access ens ha retornat. Podem navegar a través d'un ResultSet amb els mètodes first(), last(), o next(). El que fem en aquest cas és fer una lectura seqüencial del ResultSet des del primer registre fins al darrer amb un cicle while (resposta.next()) { ... }.

    A cada pas del
    cicle assignem a la variable "nomsencerusuari" la suma dels camps cognom1, cognom2 i nom de la taula usuaris:

    resposta.getString("cognom1")+" "+
    resposta.getString("cognom2")+","+
    resposta.getString("nom");

    També
    incrementem el comptador d'usuaris a cada pas del cicle.

  • Finalment, tanquem Statement, que ens tanca automàticament ResultSet, i tanquem la connexió amb la base de dades: pregunta.close() i connexio.close().
   
  Pools de connexions:
   

Establir connexions amb el motor de dades és una feina molt pesada per un servidor d'aplicacions. Consumeix bastants recursos de l'ordinador i tarda molt de temps: la nostra aplicació ha de demanar permís al motor, esperar que aquest ens reconegui i, finalment, carregar un grup de recursos en memòria.

A l'aplicació de gestió d'usuaris que vàrem escriure en el mòdul anterior obríem una connexió de dades a l'iniciar el programa i la manteníem oberta fins a la sortida. La càrrega de la creació de connexions no era crítica perquè només la cridàvem un cop per a cada instància del programa. Aquest plantejament, que resulta raonable en aplicacions client/servidor convencionals, pot és possible en un entorn web.

Quan tenim un servidor d'aplicacions en marxa a Internet, el volum de feina que ha de fer és sempre imprevisible. Podem tenir un usuari connectat però també en podem tenir mil (el nostre servidor podrà suportar mil connexions a dades?), una cosa que mai passaria en una intranet d'oficina. A més, els usuaris que accedeixen des d'internet no els tenim localitzats amb la mateixa precisió que amb aplicacions convencionals: què passa quan un usuari tanca el navegador? El servidor d'aplicacions no ho sap perquè el protocol HTTP no treballa amb el concepte de sessió d'usuari. Podem obrir una connexió permanent per a un usuari en aquest context? És possible, però també difícil i insegur.

Aquesta discontinuïtat en l'accés als recursos del servidor des d'aplicacions web s'ha corregit, des del punt de vista de l'accés a dades, amb el treball a través de servidors de connexions (pools de connexions).

La idea és molt simple: en lloc de donar una connexió per cada aplicació o per cada pàgina JSP, creeem un grup de connexions que posem en marxa quan engeguem el servidor d'aplicacions. Tota la càrrega d'establir les connexions es concentra en el primer moment, en l'engegada del servidor. Les connexions queden sempre actives i, quan una pàgina web necessita accedir a dades, en lloc de crear una nova connexió i ralentitzar el rendiment de pàgina i ordinador, li passoem una connexió que ja està oberta, una cosa molt més ràpida i barata en el consum de recursos.

També puc limitar fàcilment el nombre de connexions admisibles, per adaptar-lo a les possibilitats de la meva màquina: aquelles peticions que es fan quan totes les connexions del pool estan ocupades, s'hauran d'esperar a que el servidor n'alliberi una.

En forma d'esquema es podria representar així:

Aplicació convencional:
Inici del programa Connexió a la base de dades  
  Feina d'accés a dades  
  Feina d'accés a dades  
  Feina d'accés a dades  
  ...  
  Petició de tancament de l'aplicació  
  Desconnexió de la base de dades Sortida del programa

Aplicació web:
Apertura de la pàgina HTML Obtenció d'una connexió del pool - Feina d'accés a dades - Retorn de la connexió al pool  
  Obtenció d'una connexió del pool - Feina d'accés a dades - Retorn de la connexió al pool  
  Obtenció d'una connexió del pool - Feina d'accés a dades - Retorn de la connexió al pool  
  ...  
  Obtenció d'una connexió del pool - Feina d'accés a dades - Retorn de la connexió al pool Tancament de la pàgina HTML

Pràcticament tots els servidors d'aplicacions disposen de classes que treballen amb pools de connexions. Resin també. És gairebé imprescindible utilitzar-les si penseu fer alguna aplicació web, ni que sigui a l'àmbit de la intranet de l'institut.

   
  Crear un pool de connexions per a Resin:
   
En primer lloc li explicarem a Resin que volem crear un pool de dades. Editeu el fitxer resin.conf, que és a la carpeta /conf del directori on haureu posat Resin. Afegiu aquestes línies de codi XML després de l'etiqueta <caucho.com>:
   
 

<dbpool.sql id='biblioteca'
  driver="sun.jdbc.odbc.JdbcOdbcDriver"
  url="jdbc:odbc:biblioteca"
  user=""
  password=""
  max-connections="10"
/>

   
  A partir d'ara disposem d'un recurs que ens registra el driver JDBC i crea i permet fins un màxim de 10 connexions a la base de dades 'biblioteca'.

Observem com s'ha de cridar el pool des de Java:
   
  <%@ page import="java.sql.*,com.caucho.sql.DBPool;"%>

<html>
<head>
<title>Usuaris de la biblioteca</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>

<body bgcolor="#FFFFFF" text="#000000">
<p><font face="Arial, Helvetica, sans-serif" size="2"><b>LLISTA D'USUARIS ENREGISTRATS
AL SERVEI DE BIBLIOTECA DE L'INSTITUT</b></font></p>
<p>
<%

String nomsencerusuari="";
int comptador = 0;

DBPool pool = DBPool.getPool("biblioteca");
Connection connexio = pool.getConnection();

Statement pregunta = connexio.createStatement();
ResultSet resposta = pregunta.executeQuery("select * from usuaris "+
                                           "order by cognom1");
    while (resposta.next()) {
        nomsencerusuari = resposta.getString("cognom1")+" "+
                          resposta.getString("cognom2")+","+
                          resposta.getString("nom");
        comptador++;
%><%=nomsencerusuari%><br><%
    }
pregunta.close();
connexio.close();
%>
</p>
Actualment la biblioteca compta amb <%=comptador%> lectors/es
</body>
</html>

   
 

Hem sustituït el mecanisme de connexió convencional:

String Urldades = "jdbc:odbc:biblioteca";
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection connexio = DriverManager.getConnection(Urldades,"","");

per aquest altre:

DBPool pool = DBPool.getPool("biblioteca");
Connection connexio = pool.getConnection();

Observeu que les instruccions d'apertura i tancament de la connexió són idèntiques que amb la programació sense pool. De fet, però, ara, quan executem connexio.close() no tanquem físicament la connexió, sinó que el pool la posa a la llista de connexions disponibles.

Vigileu amb la importació de la classe DBPool al començament de la pàgina JSP: <%@ page import="java.sql.*,com.caucho.sql.DBPool;"%>!

   
   
   
 
Amunt