java - ¿Cómo usar el almacenamiento en caché de sentencias preparado MySQL?
hibernate jdbc (5)
¿Cómo aprovecho la capacidad de MySQL para almacenar en caché las declaraciones preparadas? Una razón para usar declaraciones preparadas es que no es necesario enviar la declaración preparada muchas veces si la misma declaración preparada se va a usar nuevamente.
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mydb" +
"?cachePrepStmts=true", "user", "pass");
for (int i = 0; i < 5; i++) {
PreparedStatement ps = conn.prepareStatement("select * from MYTABLE where id=?");
ps.setInt(1, 1);
ps.execute();
}
conn.close()
Al ejecutar el ejemplo de Java anterior, veo 5 pares de comandos de preparación y ejecución en el archivo de registro de mysqld. Al mover la asignación ps fuera del bucle, se obtienen, por supuesto, los comandos Preparar y 5 Ejecutar. El parámetro de conexión "cachePrepStmts = true" no parece hacer ninguna diferencia aquí.
Cuando se ejecuta un programa similar utilizando Spring e Hibernate, el número de comandos de preparación enviados (1 o 5) depende de si el parámetro de conexión cachePrepStmts está habilitado. ¿Cómo ejecuta Hibernate las declaraciones preparadas para aprovechar la configuración de cachePrepStmts? ¿Es posible imitar esto usando JDBC puro?
Estaba ejecutando esto en MySQL Server 4.1.22 y mysql-connector-java-5.0.4.jar
¿Es posible imitar esto usando JDBC puro?
¿De hecho, esto no es lo que has hecho al mover tu llamada de declaración preparada fuera del ciclo?
Es posible que esté malinterpretando la forma en que funciona la memoria caché de MySQL, pero ¿el archivo de registro necesariamente informa el trabajo de la caché? Puede ser que Spring o Hibernate tengan su propio caché intermedio que verifique las declaraciones preparadas contra las enviadas anteriormente. Puede ser que estés viendo cuando ejecutas el programa con Spring. Eso significaría rastrear un poco con su sistema para ver si el registro de mysqld solo está informando sobre las declaraciones que se han enviado, independientemente de cómo se maneje.
Debe preparar su resumen solo una vez, fuera del ciclo, y luego vincular los parámetros en el ciclo. Esta es la razón por la cual las declaraciones preparadas tienen parámetros de enlace, por lo que puede reutilizar la declaración preparada.
Hibernate hace exactamente esto, tratando todo SQL como una declaración preparada detrás de escena, aunque obviamente puede abusar de esto si usa parámetros literales en lugar de obligarlos.
Primero, su PreparedStatement se recrea en el ciclo, por lo que el controlador JDBC puede descartar los datos preparados. Entonces preguntaste por el comportamiento feo, y entonces lo obtuviste.
Y luego, PreparedStatement en MySQL es un capítulo en sí mismo. Para tener un almacenamiento en caché real, debe solicitarlo explícitamente a través de una propiedad de conexión.
Por lo tanto, debe establecer la propiedad "cachePrepStmts" en "true" para obtener el almacenamiento en caché de las declaraciones preparadas. Por defecto, esa propiedad se establece en falso.
@see el manual de MySQL para su versión de MySQL para más detalles
También necesita establecer el tamaño de caché de sentencia en la instancia de conexión. Supongo que el tamaño de caché predeterminado es 0. Por lo tanto, nada se almacenará en caché.
Debe preparar la declaración fuera del ciclo.
Connection conn = DatabaseUtil.getConnection();
PreparedStatement stmtUpdate = conn.prepareStatement("UPDATE foo SET bar=? WHERE id = ?");
for(int id=0; id<10; id++){
stmtUpdate.setString(1, "baz");
stmtUpdate.setInt(2, id);
int rows = stmtUpdate.executeUpdate();
// Clear parameters for reusing the preparedStatement
stmtUpdate.clearParameters();
}
conn.close();
No sé acerca de las declaraciones preparadas de almacenamiento en caché de mysql, pero esta es la forma en que se supone que las declaraciones preparadas de JDBC deben reutilizarse.