Как использовать подготовленное MySQL кэширование операторов? - PullRequest
8 голосов
/ 21 октября 2008

Как воспользоваться возможностью MySQL для кэширования подготовленных операторов? Одна из причин использовать подготовленные операторы заключается в том, что нет необходимости отправлять подготовленный оператор несколько раз, если один и тот же подготовленный оператор будет использоваться снова.

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

При запуске приведенного выше примера Java я вижу 5 пар команд Prepare и Execute в файле журнала mysqld. Перемещение назначения ps за пределы цикла приводит к разовым командам Prepare и 5 Execute. Параметр соединения «cachePrepStmts = true» здесь, похоже, не имеет значения.
При запуске аналогичной программы с использованием Spring и Hibernate количество отправленных команд Prepare (1 или 5) зависит от того, включен ли параметр соединения cachePrepStmts. Как Hibernate выполняет подготовленные операторы, чтобы воспользоваться настройкой cachePrepStmts? Можно ли имитировать это, используя чистый JDBC?
Я выполнял это на MySQL Server 4.1.22 и mysql-connector-java-5.0.4.jar

Ответы [ 5 ]

2 голосов
/ 04 февраля 2010

Вам также необходимо установить размер кэша операторов в экземпляре соединения. Я предполагаю, что размер кэша по умолчанию равен 0. Следовательно, ничто не будет кэшировано.

2 голосов
/ 21 октября 2008

Вы должны подготовить свой оператор только один раз, вне цикла, а затем связать параметры в цикле. Вот почему подготовленные операторы имеют параметры привязки - так что вы можете повторно использовать подготовленный оператор.

Hibernate делает именно это, рассматривая весь SQL как подготовленный оператор за кулисами, хотя вы, очевидно, можете злоупотреблять этим, если используете литеральные, а не обязательные параметры.

2 голосов
/ 21 октября 2008

Можно ли имитировать это, используя чистый JDBC?

Разве это не то, что вы сделали, переместив готовый вызов оператора из цикла?

Возможно, я неправильно понимаю, как работает кеш MySQL, но обязательно ли файл журнала сообщает о работе кеша? Может случиться так, что Spring или Hibernate имеет свой собственный промежуточный кеш, который сравнивает подготовленные операторы с теми, что были отправлены ранее. Это может быть то, что вы видите, когда запускаете программу с помощью Spring. Это будет означать, что вам нужно будет немного поработать с вашей системой, чтобы увидеть, сообщает ли журнал mysqld только об утверждениях, которые были отправлены, независимо от того, как он с ними работает.

1 голос
/ 17 декабря 2008

Вы должны подготовить оператор вне цикла.

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

Я не знаю, что такое кэшированные подготовленные операторы mysql, но именно таким образом подготовленные операторы JDBC должны использоваться повторно.

1 голос
/ 22 октября 2008

Во-первых, ваш PreparedStatement воссоздается в цикле, поэтому драйверу JDBC разрешается отбрасывать подготовленные данные. Итак, вы спросили о безобразном поведении и получили его.

И затем, PreparedStatement в MySQL - это отдельная глава. Для реального кэширования вы должны явно запросить его через свойство соединения.

Таким образом, вы должны установить свойство «cachePrepStmts» в значение «true», чтобы получить кэширование для подготовленных операторов. По умолчанию это свойство имеет значение false.

@ подробности см. В руководстве MySQL для вашей версии MySQL

...