Disseny de la persistència JDBC

50
Enginyeria del SW II: Disseny de la persistència. JDBC Disseny de la persistència JDBC Toni Navarrete Enginyeria del Software II – UPF 2003

description

Disseny de la persistència JDBC. Toni Navarrete Enginyeria del Software II – UPF 2003. Què és JDBC?. JDBC és un middleware que permet la nostra aplicació Java connectar i accedir d’una forma estandaritzada a qualsevol base de dades relacional (que disposi d’un driver JDBC) - PowerPoint PPT Presentation

Transcript of Disseny de la persistència JDBC

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Disseny de la persistènciaJDBC

Toni Navarrete

Enginyeria del Software II – UPF 2003

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 2

Què és JDBC?

• JDBC és un middleware que permet la nostra aplicació Java connectar i accedir d’una forma estandaritzada a qualsevol base de dades relacional (que disposi d’un driver JDBC)

• JDBC és present al J2SDK (des de JDK 1.1). Paquets:– java.sql– javax.sql

• El codi és independent del gestor que utilitzem– Portable– Escalable

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 3

JDBC: 4 tipus de drivers

• Hi ha quatre tipus de drivers JDBC – Tipus 1: JDBC-ODBC bridge + ODBC driver– Tipus 2: Native-API partly-Java driver

• converteix les crides de JDBC a crides de l’API pròpia del SGBD

– Tipus 3: JDBC-Net pure Java driver• Converteix les crides JDBC a un protoco de xarxa

independent del SGBD, que després és traduït al protocol del SGBD per un servidor

– Tipus 4: Native-protocol pure Java driver• Converteix les crides JDBC directament al protocol de

xarxa usat pel SGBD

• El codi dels nostres programes són independents del tipus de driver (quasi)

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 4 JDBC: Establint la connexió• La primera cosa que cal fer és establir una

connexió amb el SGBC que volem utilitzar. Això inclou dues etapes– 1. Carregar el driver– 2. Realitzar la connexió

• Carregar el driver– Instrucció:

• Class.forName(“nom_driver”);O• Class.forName(“nom_driver”).newInstance();

– La documentació del driver ens dirà quin nom hem de posar-hi. Per exemple, el driver que fa el bridge JDBC-ODBC (inclòs en el J2SDK):

• Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

– Això ho registra automàticament en el DriverManager i ja podem crear-hi connexions

– Les classes del driver han d’estar al classpath

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 5

JDBC: Connections

• Establir la connexió – Una vegada tenim registrar el driver corresponent (a

l’objecte DriverManager), ja podem crear la connexió amb el SGBD

– Objecte Connection. Exemple:• Connection con = DriverManager.getConnection(url,

“usuari", “password");

– Exemple:String url = "jdbc:odbc:miBD"; Connection con = DriverManager.getConnection(url,

“usuari", “password");

– La documentació del driver dirà com es forma la URL

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 6

JDBC: Statements

• Un objecte Statement és el que envia sentències SQL al SGBDStatement stmt = con.createStatement();

• Sobre un statement podem:– executar consultes

• amb el mètode executeQuery

– executar operacions de modificació (insert, delete, update)

• Amb el mètode executeUpdate

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 7

JDBC: ResultSets

• Els resultats després d’executar una consulta són un conjunt de files que es guarden a un objecte de la classe ResultSet

• Per exemple– ResultSet rs =

stmt.executeQuery("SELECT codi, nom FROM alumne");

• Un ResultSet té una sèrie de mètodes per recòrrer-lo fila a fila i per recuperar els valors dels camps d’una fila

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 8

JDBC: manegant els ResultSet• Exemple:

String query = "SELECT codi, nom FROM alumne"; ResultSet rs = stmt.executeQuery(query); while (rs.next()) { int codi = rs.getInt(“codi");

String nom = rs.getString(“nom"); System.out.println(codi + ": " + nom);

}

• Mètodes per recórrer el ResultSet:first() ens situa a la primera fila del ResultSetnext() avança a la següent filaisFirst() retorna un booleanisLast() retorna un boolean

• Mètodes per recuperar el valor del camp d’una fila:getString(“nom_camp”) o getString(1) Les columnes numerades des de 1getFloat(“nom_camp”) o getFloat(1)getInt(“nom_camp”) o getInt(1)...

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 9

Avantatges i inconvenients de JDBC

• Dóna accés a SQL• Usa el model relacional de SQL

– No l’orientat a objectes de Java– Procedurar en llo d’OO– El processament de dades es fa mitjançant SQL i no

Java

• Les operacions són expressades en relació a taules, files i columnes

• SQL no està realment estandaritzat, amb la qual cosa la portabilitat no sempre és real

• Procedural instead of object-oriented

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 10 Un exemple d’aplicació amb JDBCimport java.sql.*;public class ExempleJDBC { public recuperaAlumnes() { try {

Class.forName("com.mysql.jdbc.Driver"); //Nom del driver de MySQL (MySQL Connector/J) //Class.forName("oracle.jdbc.driver.OracleDriver"); //Nom del driver d'Oracle

} catch(java.lang.ClassNotFoundException e) {System.err.print("ClassNotFoundException: "); System.err.println(e.getMessage());

}String url = "jdbc:mysql://host:3306/nomBD“;

//cadena de connexió per al driver de MySQL (si el port és el 3306 no cal posar-ho)//String url = "jdbc:oracle:thin:@host:1521:nomBD"; //cadena de connexió per al driver “thin” d’Oracle

try { Connection con = DriverManager.getConnection(url, "user", "password"); //definim la connexió //Connection con = DriverManager.getConnection(url, "", ""); //si no es fa autentificat Statement stmt = con.createStatement(); // creem un statement sobre la connexió

String myquery = "SELECT codi,nom from alumnes"; ResultSet rs = stmt.executeQuery(myquery); //executem la consulta " SELECT codi,nom from alumnes "

while (rs.next()) // recorrem el recordset, fila a fila i anem afegint les "persones" al vector { int codi = rs.getInt(“codi"); String nom = rs.getString("nom"); System.out.println(codi +": " + nom); } rs.close(); // tanquem el recordset stmt.close(); // tanquem el statement con.close(); // tanquem el recordset } catch(Exception ex) { System.err.println("Exception: " + ex.getMessage()); } }...}

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 11

I en una aplicació web?

• Utilitzarem servlets i JSPs (Java Server Pages)

• S’executen en un motor de servlets (servlet-engine), també anomenat contenidor web (web-container)

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 12

Arquitectura d’un servidor web

• Exemple: Apache web server

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 13

Arquitectura d’un motor de servlets o contenidor web

• Exemple: Tomcat, Oracle IAS (Internet Application Server)

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 14

Servlets• Un servlet és una classe Java que implementa la interface

Servlet, o bé extén les classes abstractes GenericServlet o HttpServlet (el més habitual) que ja implementen aquesta interface

• HttpServlet té suport per a manegar peticions HTTP de tipus Get, Post, ..., amb els mètodes doGet o doPost– De forma genèria es pot utilitzar el mètode service

• Els paràmentres d’aquests mètodes (en el cas de HttpServlet) són:– HttpServletRequest: conté els arguments que es passen mitjançant

formularis. També, si n’hi ha, paràmetres de sessió– HttpServletResponse: l’utilitzarem per escriure la resposta que el

servlet retorna (li hem de dir el content-type)

• HttpServlet també té dos mètodes per manegar el cicle de vida del servlet: init i destroy

• HttpServlet també té altres dos mètodes que no se solen sobreescriure: getServletInfo i getServletConfig

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 15 Exemple de servlet simple public class HolaServlet extends HttpServlet { /** * gestiona les peticions GET */ public void doGet (HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException { // cal posar el content type abans d’escriure la pàgina response.setContentType("text/html");

// i ara ja podem escriure al PrintWriter PrintWriter out = response.getWriter();

out.println("<HTML><HEAD><TITLE>"); out.println(“Exemple de servlet simple”); out.println("</TITLE></HEAD><BODY>"); out.println(“<H1>Hola, soc un servlet</H1>"); out.println("</BODY></HTML>"); out.close(); } }

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 16

Exemple de servlet simple

import javax.servlet.*;import javax.servlet.http.*;public class ExempleServlet extends HttpServlet { /** Inicialització del servlet */ public void init(ServletConfig config) throws ServletException { super.init(config); }

/** Destrucció del servlet. */ public void destroy() { }

/** Processa peticions (es crida des de doGet i doPost. Escriu la pàgina que s'ha de retornar */ protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException { response.setContentType("text/html"); java.io.PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head>"); out.println("<title>Exemple de servlet simple</title>"); out.println("</head>"); out.println("<body>"); out.println("Hola, soc un servlet que respon a peticions GET i POST"); out.println("</body>"); out.println("</html>"); out.close(); }

/** s'executa quan es rep una petició GET */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException { processRequest(request, response); }

/** s'executa quan es rep una petició POST */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, java.io.IOException { processRequest(request, response); } }

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 17

Un exemple de JSP

<HTML><BODY><H1><% out.println(“Hola, soc un JSP");%></H1></BODY></HTML>

• Tot el que hi hagi entre <% i %> és codi Java• Hi ha objectes built-in (ja existents sense haver

de declarar-los). Entre d’altres:– out – request– response

• Compilació de JSPs

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 18

Un altre exemple de JSP

<%@ page contentType="text/html"%><HTML><BODY><% java.util.Calendar dataActual = new java.util.GregorianCalendar(); int mes = dataActual.get(dataActual.MONTH)+1; //comencen en 0 int dia = dataActual.get(dataActual.DAY_OF_MONTH); int any = dataActual.get(dataActual.YEAR); int hora = dataActual.get(dataActual.HOUR_OF_DAY);%>La data actual és <% out.println(dia); %> / <% out.println(mes); %> / <%

out.println(any); %><BR><B><%

if (hora<14) out.println("Bon dia!");else if (hora<20) out.println("Bona tarda!");else out.println("Bon vespre!");

%></B></BODY></HTML>

No cal posar-ho, és l’opció per defecte.

Si fos XML seria “text/xml”

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 19

Un exemple de JSP amb declaració de mètodes• Amb <%! ... %> també podem declarar

mètodes i variables d’instància que podrà ser accedida des de qualsevol mètode

<HTML><BODY><%!

public String diguesHola(){

return “Hola, soc un JSP";}

%><B><% =diguesHola() %></B></BODY></HTML>

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 20 Estructura d’una aplicació webWeb ARchives (WARs)• Per a que una aplicació amb JSPs, servlets i altres classes

pugui ser executada a qualsevol motor de servlets, es va definir WAR

• Estructura de directoris concreta i fitxer de descripció web.xml– / (arrel) on es posen els documents HTML i JSP– /WEB-INF

• web.xml (descripció)– /classes: servlets, altres classes,... (els .class)– /lib: paquets jar necessaris

– Es poden crear subdirectoris específics tant en l’arrel com al directori de les classes (WEB-INF/classes)

• Generació del WAR:– J2EE porta una eina (packager) per empaquetar i generar el WAR– També es pot fer amb jar si tenim l’estructura adequada:

• jar cvf archiveName.war ...– ant– Eines IDE (com NetBeans, SunOne,...)

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 21

Passant dades entre peticions

• HTTP no treballa amb connexions permanents (no orientat a sessió)– Com passem dades d’un servlet (o JSP) a un altre?

• Un servlet pot manegar paràmetres de formulari o URL amb un objecte HttpServletRequest (objecte built-in request en els JSP), que té el mètode:– getParameter(“nom_parametre")– Exemple:

HttpServletRequest request;String nom = (String)request.getParameter(“nomUsuari”);

– Camps ocults: problemes de seguretat

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 22

Passant dades entre peticions: sessions

• Es pot crear un objecte de sessió – Funciona com a una cookie (que no normalment no es guarda en

disc)– L’objecte de sessió es crea amb

• HttpSession session = request.getSession();

– Quan es crea la sessió, el motor de servlets envia al navegador la cookie contenint un ID de sessió

– El client (navegador) és qui guarda els paràmetres que cal mantenir al llarg de la sessió, per exemple el “login”. Utilitza els mètodes de HttpSession:

• void setAttribute(String name, Object value);– Exemple: session.setAttribute(“login”,”toni”);

• Object getAttribute(String name);– Exemple: String s = getAttribute(“login”);

• void removeAttribute(String name, Object value);

– El client després envia l’objecte de sessió de nou al servidor quan fa qualsevol petició

• Els JSPs tenen l’objecte built-in session

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 23

Forçar crear una sessió nova

• Si no es diu el contrari, s’utilitza la sessió ja creada

• Per fer una de nova:HttpSession antigaSessio =

request.getSession(false);// false indica que recuperi la sessió si n’hi havia// però que no en crei una nova sessió si no n’existia cap

if (antigaSessio != null) antigaSessio.invalidate();

HttpSession session = request.getSession(true);

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 24

Integrant JDBC i JSP/Servlets

• Dins del servlet (doGet o doPost) o del JSP (entre <% i %>) es poden incloure crides JDBC per recuperar dades de la BD i a partir dels resultats generar la pàgina de resultats

• En un JSP s’utilitza la directiva page (que hem vist abans per declarar el content-type) també per importar llibreries. Exemple:

<%@ page import=“java.sql.*”><%@ page import=“java.util.*”>

O<%@ page import=“java.sql.*, java.util.*”>

• Les classes del driver JDBC han d’estar en el classpath del motor de servlets (no en en client)

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 25

Integrant JDBC i JSP/Servlet. Exemple<%@ page import="java.sql.*" %><html><body><h1>Llista d'alumnes</h1><% Class.forName("com.mysql.jdbc.Driver").newInstance();

String url = "jdbc:mysql://localhost/test";

Connection con = DriverManager.getConnection(url, "", ""); //definim la connexió Statement stmt = con.createStatement(); // creem un statement sobre la connxió

String mysql = "SELECT codi,nom from alumnes"; ResultSet rs = stmt.executeQuery(mysql); //executem la consulta

while (rs.next()) // recorrem el recordset, fila a fila i anem afegint les "persones" al vector { int codi = rs.getInt("codi"); String nom = rs.getString("nom");%>Codi: <B><% out.print(codi); %></B>; Nom: <B><% out.print(nom);%></B><BR><% } rs.close(); // tanquem el recordset stmt.close(); // tanquem el statement con.close(); // tanquem el recordset %></body></html>

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 26

PERILL!

• És molt habitual que s’acabin barrejant totes les capes en un únic JSP (o servlet) i que l’arquitectura del sistema quedi com una xarxa immanegable de JSPs que fan cadascú una funció específica

• Desenvolupament funcional, no OO

• Solució: MVC i arquitectura en capes

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 27

Paradigma Model-View-Controller (MVC)

• Podem veure qualsevol sistema amb una divisió en 3 àrees:– Controlador (controller), que manega l’entrada que canvia el

sistema• Exemple: el volant

– Model, que són les dades o el model del sistema• Exemple: el motor, suspensió, transmissió,...

– Vista (view), que és la presentació de les dades, ja sigui de forma textual, gràfica...

• Exemple: el comptaquilòmetres, indicadors lluminosos...

• MVC és típic en desenvolupaments GUI• També una aplicació web:

– Un servlet recull les dades necessàries típicament des d’un formulari (controller)

– Hi ha una sèrie de classes que fan una sèrie d’operacions, normalment amb una BD (model)

– El resultat es mostra mitjançant altre servlet o JSP (view)

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 28

Arquitectura

• Arquitectura basada en capes– Capa de presentació– Capa de “negoci”– Capa de dades

• Arquitectura de les aplicacions– D’una capa– De dues capes– De tres capes– “Mitja capa” (exemple: 2,5 capes)

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 29

Arquitectura d’una capa

Capa de presentació

Capa de negoci

Capa de dades

Web server

File

system

Browser

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 30

Arquitectura de dues capes

Capa de presentació

Capa de negoci

Capa de dades

Web server+CGI

File

system

Browser

HTTP

Base de dades

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 31

Arquitectura de tres capes

Capa de presentació

Capa de negoci

Capa de dades

Application server

File

system

Browser

HTTP

Base de dades

JDBC

Web server

CORBA/RMI/...

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 32

Arquitectura de dues capes i mitja

Capa de presentació

Capa de presentació

Web server+servlet engine

File

system

HTTP

Capa de dades

JDBC

Browser

JavaScript

HTML dinàmic

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 33

Factors de determinació d’arquitectures de dues o tres capes

Complexitat de

l’aplicació

Mantenibilitat

Pressió de la planificació

Experiència de l’equip

de desenvolupament

Aplicacions de

2 capes

Aplicacions de

3 capes

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 34

Millores a JDBCJDBC 2.0 i posteriors

• ResultSets scrollables i updatables

• PreparedStatements

• Transaccions– Nivells d’aillament

• Pool de connexions– Datastores i registre JNDI– Exemple: DBCP per Tomcat

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 35

ResultSets scrollables i updatables• Els ResultSets scrollable permeten un accés directe (no

seqüencial) a les files d’un ResultSet • Els ResultSets updatable permeten fer modificacions sobre la BD,

no amb sentències SQL (insert, update o delete) sinó amb uns mètodes de ResultSet

• A l’hora de crear un statement des d’una connexió es poden utilitzar dos arguments:

Statement stmt = con.createStatement( ResultSet.TYPE_SCROLL_SENSITIVE,

ResultSet.CONCUR_READ_ONLY); ResultSet srs = stmt.executeQuery("SELECT id1, nom1 FROM t1");

– El primer és una de tres constants (definides a ResultSet) per indicar el tipus d’objecte ResultSet que es generarà quan s’executi una consulta.

• TYPE_FORWARD_ONLY • TYPE_SCROLL_INSENSITIVE• TYPE_SCROLL_SENSITIVE

– El segon és una de dues constants (definides a ResultSet) per indicar si l’objecte ResultSet que es genera és modificable o de només lectura:

• CONCUR_READ_ONLY • CONCUR_UPDATABLE .

– Valors per defecte: TYPE_FORWARD_ONLY i CONCUR_READ_ONLY

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 36

ResultSets scrollables i updatables

• Els ResultSet de tipus TYPE_SCROLL_INSENSITIVE i TYPE_SCROLL_SENSITIVE permeten accedir a posicions concretes del ResultSet (mentre que el TYPE_FORWARD_ONLY només es pot recórrer sequencialment)– TYPE_SCROLL_INSENSITIVE no reflecteix els canvis que poden

haver al ResultSet mentre és obert, mentre que TYPE_SCROLL_SENSITIVE sí

• Example:srs.absolute(4); // cursor is on the fourth rowsrs.relative(-3); // cursor is on the first row srs.relative(2); // cursor is on the third row

• Quatre mètodes addicionals permeten verificar si el cursos és a una determinada posició: isFirst , isLast , isBeforeFirst , isAfterLast

• Amb els mètodes updateInt, updateString,..., es poden fer canvis en el ResultSet (si s’ha declarat CONCUR_UPDATABLE) i després d’executar el mètode updateRow es modifiquen directament a la taula

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 37

ResultSets scrollables i updatablesExemple de modificació de fila

Connection con = DriverManager.getConnection("jdbc:mysql://localhost/test");

Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);

ResultSet uprs = stmt.executeQuery(“Select codi,nom,edat from alumnes”);

uprs.last(); uprs.updateString(“nom", “Pep”);uprs.updateInt(“edat”,19); uprs.updateRow();

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 38

ResultSets scrollables i updatablesInserció i esborrat d’una fila

• També es poden inserir i eliminar files directament des del RecordSet:uprs.moveToInsertRow(); uprs.updateInt(“codi”,27);uprs.updateString(“nom", “Pep”);uprs.updateInt(“edat”,19); uprs.insertRow();

uprs.absolute(4); uprs.deleteRow();

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 39

Prepared Statements

• Si s’ha d’executar la mateixa sentència SQL moltes vegades, podem reduir el temps d’execució utilitzant un objecte PreparedStatement en lloc del Statement

• La principal característica d’un objecte PreparedStatement és que ja se li dóna un SQL quan és creat

• Aquesta sentència SQL té variables de binding a les quals es donaran valors concrets abans d’executar

• Així s’estalvia a l’intèrpret SQL del SGBD haver de parsejar cada cop la mateixa sentència, només ho fa un cop i la guarda

• Example:PreparedStatement updateAlus = con.prepareStatement(“UPDATE

alumnes SET nom = ? WHERE id = ? ");

updateAlus.setString(1, “Anna");

updateAlus.setInt(2, 3);

updateSales.executeUpdate();

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 40

Prepared Statements (en un bucle)Exemple

...PreparedStatement updateAlus;String updateString = "update ALUMNES set nom = ?

where codi = ?";updateAlus = con.prepareStatement(updateString);int [] codis = {3, 5,8,12};String [] noms = {“Pep", "Joana“,”Núria”,”Anna”};int len = codis.length;for(int i = 0; i < len; i++) {

updateAlus.setString(1, noms[i]);updateAlus.setInt(2, codis[i]);updateAlus.executeUpdate();

}

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 41

Transaccions (desactivar autocommit)• Per defecte, cada sentència SQL quan és executada prova un

commit• Per definir una transacció podem desactivar això i especificar quan

volem que es faci el commit• Exemple:

con.setAutoCommit(false); PreparedStatement updateAlus;

String updateString = "update ALUMNES set nom = ? where codi = ?";

updateAlus = con.prepareStatement(updateString);int [] codis = {3, 5,8,12};String [] noms = {“Pep", "Joana“,”Núria”,”Anna”};int len = codis.length;for(int i = 0; i < len; i++) {

updateAlus.setString(1, noms[i]);updateAlus.setInt(2, codis[i]);updateAlus.executeUpdate();

}con.commit();con.setAutoCommit(true);

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 42

Transaccions (rollback)

• En cas de què es produeixi una excepció, cal fer un rollback per desfer totes les sentències que ja s’haguessin executat

• Exemple (continuant l’anterior) } catch(SQLException ex) {

System.err.println("SQLException: " + ex.getMessage());if (con != null) {

try {System.err.print("Transaction is being

");System.err.println("rolled back");con.rollback();

} catch(SQLException excep) {System.err.print("SQLException: ");

System.err.println(excep.getMessage());}

}}

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 43

Transaccions (tipus de nivells de aïllament)• La classe Connection té el mètode:

public void setTransactionIsolation(int level) throws SQLException

• Aquest mètode permet canviar el nivell d’aïllament de les transaccions, sempre que el SGBD el soporti. Aquests nivells estan especificats per les següents constants

• Aquest mètode no pot ser cridat al mig d’una transacció static int TRANSACTION_NONE

Indica que el SGBD no soporta transaccionsstatic int TRANSACTION_READ_UNCOMMITTED

Poden ocórrer “dirty reads”, “non-repeatable reads” i “phantom reads”static int TRANSACTION_READ_COMMITTED

Evita que es produeixin “dirty-reads”. Un dirty-read passa quan una transacció modifica una fila i aquesta és llegida poer una altra transacció abans que s’hagi fet el commit. Si després es produís un rollback en la primera transacció, la segona tindria una dada errònia. Resumint, no permet llegir d’una fila que s’ha modificat fins que no es fa el commit

• Continua ...

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 44

Transaccions (tipus de nivells de aïllament)• ... continuastatic int TRANSACTION_REPEATABLE_READ

Evita també les “non-repeatable reads”. Això passa quan una transacció llegeix una fila, una segona l’altera i la primera torna a llegir-la, obtenint un valor diferent-

static int TRANSACTION_SERIALIZABLE

Evita totes: “dirty reads”, “non-repeatable reads” i “phantom reads”. Un “phantom read” es produeix quan una transacció llegeix totes les files que satisfan una condició where i una segona transacció inserta una nova fila que satisfà aquesta condició where. Si la primera transacció re-llegeix es trobarà amb aquesta “fila fantasma” que abans no existia

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 45

JDBC: Connection pooling

• Una de les operacions més costoses és establir la connexió amb la base de dades

• Solució: utilització d’un pool de connexions– Es generen un conjunt de connexions– Quan una connexió demana una connexió se li assigna una

que ja existeix al pool– Si no n’hi ha disponibles, s’espera un cert temps– Un cop que s’ha utilitzat una connexió no es destrueix, queda

al pool (cal tancar-la expressament!)– Una implementació d’un pool simple a pool_simple.zip

• Amb una pila

• Si quan s’ha de fer una connexió el pool està buit, se’n crea una de nova. Si no, se’n treu una del pool

• Problemes d’aquesta implementació: el pool creix sense límit

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 46

JDBC: Connection pooling• JDBC va incorporar una forma estandaritzada per definir

un pool de forma transparent: és el servidor d’aplicacions qui ho manega i no el programador– Cal utilitzar JNDI i definir un DataSource

• JNDI ("Java Naming Directory Interface") és una especificació que permet localitzar informació en diferents directoris distribuïts

• Tomcat ho implementa amb el paquet DBCP (DataBase Connection Pool)– Cal baixar el jar i copiar-lo al directori

$CATALINA_HOME/common/lib/ on $CATALINA_HOME és el directori base on Tomcat està

instal·lat

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 47

JDBC: Connection pooling

• El codi de l’aplicació gairebé no canvia– Per obtenir la connexió no es fa a partir del DriverManager sinó

d’un DataSource Context init = new InitialContext(); Context ctx = (Context) init.lookup("java:comp/env");

//els datasources sempre estan definits a comp/env DataSource ds = (DataSource)ctx.lookup("jdbc/poolBD"); if (ds != null) Connection conn = ds.getConnection();

/* serà Tomcat qui s’encarregarà d’assignar una connexió * del pool, de forma transparent pel nostre codi */

– Cal tancar sempre la connexió!! Moltes vegades s’afegeix al try principal:

try { ...} finally { if (conn != null) conn.close();}

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 48

JDBC: Connection pooling

• En el fitxer web.xml de l’aplicació cal dir que s’utilitzarà el recurs poolDB, que és un DataSource:

<web-app> <description>MySQL Test App</description> <resource-ref> <description>DB Connection</description> <res-ref-name>jdbc/poolBD</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref></web-app>

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 49

JDBC: Connection pooling• A més, cal definir el recurs poolDB. Es fa quan es defineix el context en el fitxer server.xml de Tomcat:

<Context path="/poolTest" docBase="poolTest" debug="5" reloadable="true" crossContext="true">

<Logger className="org.apache.catalina.logger.FileLogger" prefix="localhost_DBTest_log." suffix=".txt" timestamp="true"/>

<Resource name="jdbc/poolBD" auth="Container" type="javax.sql.DataSource"/>

<ResourceParams name="jdbc/poolBD"> <parameter> <name>factory</name> <value>org.apache.commons.dbcp.BasicDataSourceFactory</value> </parameter>

<!-- Maximum number of dB connections in pool. Make sure you configure your mysqld max_connections large enough to handle all of your db connections. Set to 0 for no limit. -->

<parameter> <name>maxActive</name> <value>100</value> </parameter>

• Continua ...

En

gin

yeri

a d

el S

W II

: Dis

sen

y d

e la

pe

rsis

tèn

cia

. JD

BC

Pàgina 50

JDBC: Connection pooling• ... continua<!-- Maximum number of idle dB connections to retain in pool. Set to 0 for no limit. --> <parameter> <name>maxIdle</name> <value>30</value> </parameter>

<!-- Maximum time to wait for a dB connection to become available in ms, in this example 10 seconds. An Exception is thrown if this timeout is exceeded. Set to -1 to wait indefinitely. -->

<parameter> <name>maxWait</name> <value>10000</value> </parameter>

<!-- Class name for mm.mysql JDBC driver --> <parameter> <name>driverClassName</name> <value>com.mysql.jdbc.Driver</value> </parameter>

<!-- The JDBC connection url for connecting to your MySQL dB. The autoReconnect=true argument to the url makes sure that the com.mysql JDBC Driver will automatically reconnect if mysqld closed the connection. mysqld by default closes idle connections after 8 hours. -->

<parameter> <name>url</name> <value>jdbc:mysql://localhost:3306/test</value> </parameter> </ResourceParams></Context>