Disseny de la persistència JDBC

Slides:



Advertisements
Presentaciones similares
FUNDAMENTALS OF THE JAVA PROGRAMMING LANGUAGE
Advertisements

Acceso a Bases de Datos con Java
Fernando Alonso Blázquez Servlets con acceso a Bases de Datos 29 de Abril de 2004.
Francisco Moreno Bases de Datos II Universidad Nacional
M.I. María Luisa González Ramírez Servlets y JSP.
Tema 3 J2EE Java Database Connectivity Temas Selectos de Cómputo Grupo 912.
ARCHIVOS Y CONEXIÓN A BASE DE DATOS. FileInputStream: Clase que representa ficheros de texto accedidos en orden secuencial, byte a byte. FileWriter: Clase.
Fernando Alonso Nicolás Serrano Acceso a Bases de Datos con Java JDBC 01 de Abril de 2008.
Programación Orientada a Objetos Modulo 7 JDBC Universidad de Chile Departamento de Ciencias de la Computación.
Fernando Alonso Nicolás Serrano Servlets con acceso a Bases de Datos 21 de Abril de 2008.
JDBC Java Database Connectivity CC52N - Computación para el trabajo grupal Profesor: Nélson Baloian Por: Edgard Pineda.
1 Programación Interactiva JDBC Escuela de Ingeniería de Sistemas y Computación Facultad de Ingeniería Universidad del Valle.
Java Data Base Connectivity
Universidad de Chile - Tupper 2007, Santiago - Fono/Fax: (56 2) cec.uchile.cl Módulo ECI - 11: Fundamentos de Redes de Computadores.
Crear Aplicación Cliente para Conectarse a una Base de Datos.
Francisco Moreno Bases de Datos II Universidad Nacional
Conferencia 9. ODBC, OLE DB y JDBC.
EL NOU CATÀLEG DE LA BIBLIOTECA de l’escola
PROPORCIONALITAT 1 Funciona amb “clics”.
Projecte Fi de Carrera Disseny i desenvolupament d’un esquema criptogràfic per gestionar de forma segura els historials mèdics dels pacients a través d’una.
Aplicacions web bàsiques Introducció a servlets i JSP
Treball Fi de Carrera – J2EE
Exportar qualificacions a les actes
TFC Intranet Escolar Desenvolupament d’una aplicació Java2 EE
Aplicacions web bàsiques Introducció a servlets i JSP
Introducció de TEDIs (COACs) Versió 4.0
ESecretaria CB Montpedrós
Presentació de la base de dades
FUNCIONAMENT DE L’EPÈRGAM
ENFISPO.
Un exemple de Màquina Virtual: el programa VMware
Creació d’un mapa personalitzat
PubMed i el gestor de revistes del CRAI de la UB (servei SFX)
SISTEMA GESTOR D’EMPRESA D’EXCAVACIONS
Estudi de components ASP per al tractament ‘off line’ d’imatges
PERIFÈRICS ... Descobreix el que envolta l’ordinador!
Les Restriccions d’accés
Tutorials Campus Virtual Càrrega automàtica d’alumnes
Disseny de la persistència JDBC
Matemàtiques 3er E.S.O..
Writer Fora dels límits!
Disseny de la persistència Serialització
Objectiu Educatiu Trienni
Java DataBase Connectivity (JDBC)
Presentació BATXILLERAT
Jonathan Ceballos Rodriguez ( ) Zenón Perisé Alía ( )
Tema 5: Nombres naturals i enters
Optimització de consultes en MySQL (unes notes)
Disseny de la persistència Introducció i mapping objecte/relacional
Explicació de l’enunciat
SCIENCE OF SYNTHESIS.
CONNEXIONS SENSE CABLES I DISPOSITIUS MÒBILS
Disseny de la persistència Introducció i mapping objecte/relacional
Aplicacions web bàsiques Introducció a servlets i JSP
Disseny de la persistència Serialització
Estructurant les aplicacions MVC JSTL Struts
Java Database Connectivity JDBC
XXIII OLIMPìADA MATEMÀTICA 2012
JDBC: comunicación Java-Base de Datos
INTERNET XARXA: Quan un conjunt d’ordinadors estan connectats entre si per comunicar-se i compartir informació. TIPUS DE XARXES: LAN: Xarxa d’àrea local,
REAXYS.
Threads en Java David Gañán Jiménez.
Xavi Fabregat 4tA Karim Atsailali 4tA
Projecte Fi de Carrera - J2EE Alumne: Daniel Clemente Marcè
Estudiant: Eva Muñoz Altimis
MORFOLOGIA i SINTAXI PRONOMS RELATIUS i PRONOMS INTERROGATIUS
Projecte: Videojocs.cat
Exportar qualificacions a les actes
Estils i Plantilles Ms Word.
Pàgina El problema de l’origen del coneixement i la veritat 1.3 La recerca d’un criteri de veritat La crítica al dubte metòdic cartesià i el seu.
Transcripción de la presentación:

Disseny de la persistència JDBC Toni Navarrete Enginyeria del Software II – UPF 2006

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

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. Els applets no els poden utilitzar per raons de seguretat Tipus 3: JDBC-Net pure Java driver Converteix les crides JDBC a un protocol de xarxa independent del SGBD (per exemple SQL*Net), que després és traduït al protocol del SGBD per un servidor. Aquest servidor middleware permet connectar a diferents SGBDs. Molt flexible, però han de solventar aspectes de seguretat, firewalls,... Tipus 4: Native-protocol pure Java driver Converteix les crides JDBC directament al protocol de xarxa usat pel SGBD (per exemple Oracle CLI). Suposa una crida directa de la màquina client al servidor SGBD. Com que solen ser protocols propietaris, els drivers els desenvolupen els fabricants dels propis SGBDs El codi dels nostres programes són independents del tipus de driver (quasi)

JDBC: Establint la connexió La primera cosa que cal fer és establir una connexió amb el SGBD 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

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"; La documentació del driver dirà com es forma la URL

Un objecte Statement és el que envia sentències SQL al SGBD JDBC: Statements Un objecte Statement és el que envia sentències SQL al SGBD Statement 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

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

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 ResultSet next() avança a la següent fila isFirst() retorna un boolean isLast() 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 1 getFloat(“nom_camp”) o getFloat(1) getInt(“nom_camp”) o getInt(1) ...

Un exemple d’aplicació amb JDBC import 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 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()); ...}

JDBC 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)

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 el client)

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>

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 (Model-View-Controller) i separació en capes (presentació, “negoci” i dades)

Avantatges i inconvenients de JDBC Dóna accés a SQL Usa el model relacional de SQL No l’orientat a objectes de Java Procedural en lloc 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 Procedimental en lloc d’orientat a objectes

Millores a JDBC JDBC 2.0 i posteriors ResultSets scrollables i updatables PreparedStatements Transaccions Nivells d’aillament Pool de connexions Datastores i registre JNDI Exemple: DBCP per Tomcat

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

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); // el cursor se situa a la fila 4 srs.relative(-3); // el cursor se situa a la fila 1 srs.relative(2); // el cursor se situa a la fila 3 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

ResultSets scrollables i updatables Exemple 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();

ResultSets scrollables i updatables Inserció 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();

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();

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(); }

Transaccions (desactivar autocommit) Per defecte, cada sentència SQL quan és executada provoca 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);

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("Transacció abortada"); con.rollback(); } catch(SQLException excep) { System.err.print("Excepció de SQL: "); System.err.println(excep.getMessage()); }

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 transaccions static 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 per 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 ...

Transaccions (tipus de nivells de aïllament) ... continua static 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 La classe Connection també té un mètode per saber el nivell d’aïllament actual: int getTransactionIsolation() TRANSACTION_NONE: 0 TRANSACTION_READ_UNCOMMITTED: 1 TRANSACTION_READ_COMMITTED: 2 TRANSACTION_REPEATABLE_READ: 4 TRANSACTION_SERIALIZABLE: 8

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 classe (o JSP) 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

JDBC: Connection pooling JDBC va incorporar una forma estandaritzada per definir un pool de forma transparent (mitjançant una sèrie d’interfícies): serà el servidor d’aplicacions qui ho manegarà 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 mitjançant DBCP (DataBase Connection Pool) En la versió 5.5 i posteriors està integrat en la distribució de Tomcat, en el paquet “naming-factory-dbcp.jar”

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(); }

JDBC: Connection pooling En el fitxer web.xml de l’aplicació cal dir que s’utilitzarà el recurs poolBD, que és un DataSource: <web-app> <description>Prova del pool amb DBCP </description> <resource-ref> <description>Connexio amb BD</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>

JDBC: Connection pooling A més, cal definir el recurs poolDB. Es fa quan es defineix el context en el context.xml de l’aplicació, al directori META-INF: <?xml version="1.0" encoding="UTF-8"?> <Context path="/dbcp"> <Logger className="org.apache.catalina.logger.FileLogger" prefix="dbcp." suffix=".log" timestamp="true"/> <Resource name="jdbc/poolBD" auth="Container" type="javax.sql.DataSource" username="usuari" password="password" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://host:3306/poolBD" maxActive="8" maxIdle="4" maxWait="10000" /> </Context> Per defecte utilitza el pool de DBCP, però es pot configurar un altre