// 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"); }
Las consultas preparadas son altamente intersantes por cuestiones de eficacia, seguridad y rendimiento.
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(); } } }
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 |
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>
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.
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.
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();
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