User Tools

Site Tools


java:jdbc

JDBC

Un ejemplo sencillo

// Creamos un objeto conexión especificando la clase 
// de driver que vamos a usar
Connection con = DriverManager.getConnection
           ( "jdbc:myDriver:wombat", "myLogin","myPassword");
 
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table1");
 
// recorremos el resulset. rs está en la posición 0, 
// de tal forma que la llamada a rs.next() lo posiciona
// en el primer elemento 
while (rs.next()) 
{
  int x = rs.getInt("a");
  String s = rs.getString("b");
  float f = rs.getFloat("c");
}

Ejemplo de consulta preparada

Las consultas preparadas son altamente intersantes por cuestiones de eficacia, seguridad y rendimiento.

Cómo funciona una consulta preparada

El cliente primero manda la consulta, que es algo del tipo “select * from tabla where id = ?”, donde la interrogación corresponde a un parámetro.

La base de datos, una vez que ha recibido la consulta, la puede compilar y optimizar.

A continuación, se mandan los parámetros, que son reemplazados por las interrogaciones y se ejecuta la consulta.

Las ventajas son evidentes: ya que en casos de consultas que se repitan con frecuencia, nos ahorramos el paso de compilar y optimizar.

Además tenemos una ventaja en seguridad, ya que es mucho más difícil cometer el nefasto error de la inyección SQL.

import java.sql.*;
 
public class UpdateCar {
 
    public static void UpdateCarNum(int carNo, int empNo)
                                              throws SQLException {
        Connection con = null;
        PreparedStatement pstmt = null;
 
        try {
          con = DriverManager.getConnection("jdbc:default:connection");
 
            pstmt = con.prepareStatement(
                        "UPDATE EMPLOYEES SET CAR_NUMBER = ? " +
                        "WHERE EMPLOYEE_NUMBER = ?");
            pstmt.setInt(1, carNo);
            pstmt.setInt(2, empNo);
            pstmt.executeUpdate();
        }
        finally {
            if (pstmt != null) pstmt.close();
        }
    }
}

Recogiendo valores de los resultsets

Los resultSets son los objetos que almacenan los resultados de una consulta.

A la hora de crear el comando se puede configurar el tipo de resultset que queremos que nos devuelva la consulta una vez ejecutada:

Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
                                     ResultSet.CONCUR_READ_ONLY);
ResultSet srs = stmt.executeQuery("SELECT COF_NAME, PRICE FROM COFFEES");
Valor Qué significa
ResultSet.TYPE_FORWARD_ONLY El resultset sólo se puede consultar hacia adelante, no se puede reposicionar hacia atrás ni mover arbitrariamente
ResultSet.TYPE_SCROLL_INSENSITIVE Se puede mover arbitrariamente a cualquier posición, y moverse hacia atrás en el resultset
ResultSet.TYPE_SCROLL_SENSITIVE Se puede mover arbitrariamente a cualquier posición, y moverse hacia atrás en el resultset
ResultSet.CONCUR_READ_ONLY Supongo que será de sólo lectura
ResultSet.CONCUR_UPDATABLE Lectura y escritura

Otro ejemplo utilizando un datasource

Connection con = null;
Statement stmt = null;
ResultSet rs = null;
try 
{
    Class.forName("com.mysql.jdbc.Driver");
 
    con = DriverManager.getConnection(
    "jdbc:mysql://localhost/logins", "root", "");
 
    stmt = con.createStatement(); 
 
    rs = stmt.executeQuery(
        "SELECT * FROM users " +
        "WHERE username = '" + username + "' " +
        "AND password = '" + password + "'");
 
    if (rs.next())
        valid = true;
} 
    catch (ClassNotFoundException e) {
    e.printStackTrace();
}
    catch(SQLException e) {
        e.printStackTrace();
}
finally 
{
    try { if (rs != null) rs.close(); } catch (SQLException e) {};
    try { if (stmt != null) stmt.close(); } catch (SQLException e) {};
    try { if (con != null) con.close(); } catch (SQLException e) {};
}
return valid;

Tenemos que definir el datasource en un fichero de configuración:

<data-sources>
  <data-source key="logins" type="org.apache.commons.dbcp.BasicDataSource">
    <set-property property="description" value="Music Collection Database" /> 
    <set-property property="driverClassName" value="com.mysql.jdbc.Driver" /> 
    <set-property property="username" value="root" /> 
    <set-property property="password" value="" /> 
    <set-property property="url" value="jdbc:mysql://localhost/logins" /> 
  </data-source>
</data-sources>

Transacciones en JDBC

Para ejecutar varios comandos en modo transaccional lo primero que tenemos que hacer es deshabilitar el AutoCommit. El “AutoCommit” implica que cada vez que se ejecuta un comando, bien con executeUpdate, o con executeQuery, se hace un commit automáticamente.

con.setAutoCommit(false);
PreparedStatement updateSales = con.prepareStatement(
    "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ?");
updateSales.setInt(1, 50);
updateSales.setString(2, "Colombian");
updateSales.executeUpdate();
PreparedStatement updateTotal = con.prepareStatement(
    "UPDATE COFFEES SET TOTAL = TOTAL + ? WHERE COF_NAME LIKE ?");
updateTotal.setInt(1, 50);
updateTotal.setString(2, "Colombian");
updateTotal.executeUpdate();
con.commit();
con.setAutoCommit(true);

Al ejecutar commit() se hacen los dos updates a la vez.

Nivel de isolation en transaccion

One example of a transaction isolation level is TRANSACTION_READ_COMMITTED, which will not allow a value to be accessed until after it has been committed. In other words, if the transaction isolation level is set to TRANSACTION_READ_COMMITTED, the DBMS does not allow dirty reads to occur. The interface Connection includes five values which represent the transaction isolation levels you can use in JDBC.

Normally, you do not need to do anything about the transaction isolation level; you can just use the default one for your DBMS. JDBC allows you to find out what transaction isolation level your DBMS is set to (using the Connection method getTransactionIsolation) and also allows you to set it to another level (using the Connection method setTransactionIsolation). Keep in mind, however, that even though JDBC allows you to set a transaction isolation level, doing so has no effect unless the driver and DBMS you are using support it.

Haciendo rollback (hasta un punto de guarda)

Statement stmt = conn.createStatement();
int rows = stmt.executeUpdate("INSERT INTO TAB1 (COL1) VALUES " +
                                                    "(?FIRST?)");
// set savepoint
Savepoint svpt1 = conn.setSavepoint("SAVEPOINT_1");
rows = stmt.executeUpdate("INSERT INTO TAB1 (COL1) " +
                                           "VALUES (?SECOND?)");
...
conn.rollback(svpt1);
...
conn.commit();

Insertar un tipo de datos BLOB en Oracle

No es algo trivial porque el driver JDBC de oracle funciona mal. Aquí está un ejemplo de código que funciona:

/**
 * OracleBlobSetBinaryStream.java
 * Copyright (c) 2007 by Dr. Herong Yang. All rights reserved.
 */
import java.io.*;
import java.sql.*;
public class OracleBlobSetBinaryStream {
  public static void main(String [] args) {
    Connection con = null;
    try {
      oracle.jdbc.pool.OracleDataSource ds 
        = new oracle.jdbc.pool.OracleDataSource();
      ds.setDriverType("thin");
      ds.setServerName("localhost");
      ds.setPortNumber(1521);
      ds.setDatabaseName("XE");
      ds.setUser("Herong");
      ds.setPassword("TopSecret");
      con = ds.getConnection();
 
// Deleting the record for re-testing
      String subject = "Test of setBinaryStream() methods";
      Statement sta = con.createStatement(); 
      sta.executeUpdate("DELETE FROM Image WHERE Subject = '"
        +subject+"'");
 
// Inserting CLOB value with a PreparedStatement
      PreparedStatement ps = con.prepareStatement(
        "INSERT INTO Image (ID, Subject, Body) VALUES (3,?,?)");
      ps.setString(1, subject);
      InputStream bodyIn = 
        new FileInputStream("OracleBlobSetBinaryStream.class");
 
// Test 1 - This will not work with JDBC 3.0 drivers
//    ps.setBinaryStream(2, bodyIn);
 
// Test 2 - This will not work with JDBC 3.0 drivers
//    File fileIn = new File("OracleBlobSetBinaryStream.class");
//    ps.setBinaryStream(2, bodyIn, fileIn.length());
 
// Test 3 - This works with JDBC 3.0 drivers
      File fileIn = new File("OracleBlobSetBinaryStream.class");
      ps.setBinaryStream(2, bodyIn, (int) fileIn.length());
 
      int count = ps.executeUpdate();
      bodyIn.close();
      ps.close();
 
// Retrieving BLOB value with getBytes()
      sta = con.createStatement(); 
      ResultSet res = sta.executeQuery("SELECT * FROM Image" 
        +" WHERE Subject = '"+subject+"'");
      res.next();
      System.out.println("The inserted record: "); 
      System.out.println("   Subject = "+res.getString("Subject"));
      System.out.println("   Body = "
        +new String(res.getBytes("Body"),0,32)); 
      res.close();
 
      sta.close();
      con.close();
    } catch (Exception e) {
      System.err.println("Exception: "+e.getMessage());
      e.printStackTrace();
    }
  }
}

Este ejemplo lo he sacado de esta página:

http://www.herongyang.com/jdbc/Oracle-BLOB-setBinaryStream.html

java/jdbc.txt · Last modified: 2011/03/19 20:37 (external edit)