2010-06-07 23 views
19

Estoy usando la plantilla JDBC y quiero leer desde una base de datos usando declaraciones preparadas. Repito sobre muchas líneas en un archivo .csv, y en cada línea ejecuto algunas consultas de selección de SQL con los valores correspondientes.Uso de declaraciones preparadas con JDBCTemplate

Quiero acelerar mi lectura de la base de datos, pero no sé cómo hacer que la plantilla JDBC funcione con las declaraciones preparadas.

Está el PreparedStatementCreator y el PreparedStatementSetter. Como en this example ambos se crean con clases internas anónimas. Pero dentro de la clase PreparedStatementSetter no tengo acceso a los valores que quiero establecer en la declaración preparada.

Como estoy iterando a través de un archivo .csv, no puedo codificarlos como una cadena porque no los conozco. Tampoco puedo pasarlos a PreparedStatementSetter porque no hay argumentos para el constructor. Y establecer mis valores al final sería tonto también.

Estaba acostumbrado a la creación de declaraciones preparadas siendo bastante simple. Algo así como

PreparedStatement updateSales = con.prepareStatement(
    "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ? "); 
updateSales.setInt(1, 75); 
updateSales.setString(2, "Colombian"); 
updateSales.executeUpdate(): 

como en este Java tutorial.

Respuesta

2

He intentado una instrucción select ahora con un PreparedStatement, pero resultó que no era más rápido que la plantilla Jdbc. Tal vez, como mezmo sugirió, crea automáticamente declaraciones preparadas.

De todos modos, la razón de que mi sql SELECT fuera tan lenta fue otra. En la cláusula WHERE siempre usé el operador LIKE, cuando todo lo que quería hacer era encontrar una coincidencia exacta. Como descubrí LIKE busca un patrón y, por lo tanto, es bastante lento.

Ahora estoy usando el operador = y es mucho más rápido.

9

intente lo siguiente:

PreparedStatementCreator creator = new PreparedStatementCreator() { 
    @Override 
    public PreparedStatement createPreparedStatement(Connection con) throws SQLException { 
     PreparedStatement updateSales = con.prepareStatement(
     "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ? "); 
     updateSales.setInt(1, 75); 
     updateSales.setString(2, "Colombian"); 
     return updateSales; 
    } 
}; 
+0

Esto funcionaría, pero los valores que quiero establecer están fuera de la clase anónima interna. Dentro de la clase debería haber algo como 'updateSales.setString (2, fileRow.getName())' pero no puedo acceder al formulario 'fileRow' dentro de la clase. –

+6

marque el archivo varRow como final – Inv3r53

3

me gustaría factorizar el manejo de al menos un método de la declaración preparada. En este caso, ya que no hay resultados es bastante simple (y suponiendo que la conexión es una variable de instancia que no cambia):

private PreparedStatement updateSales; 
public void updateSales(int sales, String cof_name) throws SQLException { 
    if (updateSales == null) { 
     updateSales = con.prepareStatement(
      "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ?"); 
    } 
    updateSales.setInt(1, sales); 
    updateSales.setString(2, cof_name); 
    updateSales.executeUpdate(); 
} 

En ese punto, entonces es sólo una cuestión de llamar a:

updateSales(75, "Colombian"); 

¿Qué es bastante simple de integrar con otras cosas, sí? Y si llama al método muchas veces, la actualización solo se construirá una vez y eso hará las cosas mucho más rápidas. Bueno, suponiendo que no hagas cosas locas como hacer cada actualización en su propia transacción ...

Ten en cuenta que los tipos son fijos. Esto se debe a que para cualquier consulta/actualización en particular, debe ser fijo para permitir que la base de datos haga su trabajo de manera eficiente. Si solo está tirando cadenas arbitrarias de un archivo CSV, páselos como cadenas. Tampoco hay bloqueo; mucho mejor para mantener las conexiones individuales para ser utilizado a partir de un solo hilo en su lugar.

+0

Para las consultas que devuelven un valor único, es muy fácil utilizar esta técnica también. La complejidad principal se produce cuando tienes consultas que devuelven muchos valores; cualquiera devuelve un 'ResultSet' luego o pasa una devolución de llamada que manejará cada fila devuelta (con los valores descompuestos del' ResultSet' por supuesto). –

+1

Lo siento, pero no sé qué tiene que ver eso con mi problema con la plantilla jdbc. No puedo alimentar una consulta de plantilla jdbc con un PreparedStatement. Parece que necesito un 'PreparedStatementCreator' o un' PreparedStatementSetter'. –

24

Por defecto, el JDBCTemplate hace su propio PreparedStatement internamente, si solo usa el formulario .update(String sql, Object ... args). Spring y su base de datos administrarán la consulta compilada para usted, para que no tenga que preocuparse por abrir, cerrar, proteger recursos, etc. Una de las gracias de ahorro de Spring. A link to Spring 2.5's documentation on this. Espero que aclare las cosas. Además, el almacenamiento en caché de sentencias se puede realizar en el nivel JDBC, como en el caso de at least some of Oracle's JDBC drivers. . Esto entrará en muchos más detalles de los que puedo hacer de manera competente.

+3

Pero quiero realizar una selección en la base de datos, no una actualización. En Spring, se escribe http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/jdbc/core/JdbcTemplate.html, que con 'update' solo inserta, actualiza o elimina puede ser llevado a cabo. –

+0

@ user3211068 hay un método de 'consulta' que puede seleccionar – linqu

+1

@mezmo ¿le importaría agregar una fuente para su extracto? Y es lo mismo cierto para la consulta (String sql, ...)? – leo

14
class Main { 
    public static void main(String args[]) throws Exception { 
     ApplicationContext ac = new 
      ClassPathXmlApplicationContext("context.xml", Main.class); 
     DataSource dataSource = (DataSource) ac.getBean("dataSource"); 
// DataSource mysqlDataSource = (DataSource) ac.getBean("mysqlDataSource"); 

     JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); 

     String prasobhName = 
     jdbcTemplate.query(
      "select first_name from customer where last_name like ?", 
      new PreparedStatementSetter() { 
       public void setValues(PreparedStatement preparedStatement) throws 
       SQLException { 
        preparedStatement.setString(1, "nair%"); 
       } 
      }, 
      new ResultSetExtractor<Long>() { 
       public Long extractData(ResultSet resultSet) throws SQLException, 
       DataAccessException { 
        if (resultSet.next()) { 
         return resultSet.getLong(1); 
        } 
        return null; 
       } 
      } 
     ); 
     System.out.println(machaceksName); 
    } 
} 
+0

la parte de consulta como java 8 estilo lambda: 'jdbcTemplate.query (sql, ps -> ps.setString (1," valor "), (rs, i) -> rs.getLong (1)' –

Cuestiones relacionadas