Ответ 1
Во-первых, важно различать клиентские и серверные подготовленные операторы.
Подготовленные клиентом заявления
Готовые заявления клиента являются "эмулированными" подготовленными операциями. Это означает, что строка оператора SQL маркируется на стороне клиента, а любые заполнители заменяются литеральными значениями перед отправкой оператора на сервер для выполнения. Полная инструкция SQL отправляется на сервер при каждом выполнении. Вы можете использовать общий журнал для изучения того, как это работает. например.
следующий код:
ps=conn.prepareStatement("select ?")
ps.setInt(1, 42)
ps.executeQuery()
ps.setInt(1, 43)
ps.executeQuery()
будет отображаться в журнале:
255 Query select 42
255 Query select 43
"Запрос" указывает, что на уровне протокола команда COM_QUERY
отправляется с следующей строкой оператора.
Подготовленные отчеты сервера
Подготовленные сервером операторы являются "истинными" подготовленными операциями, означающими, что текст запроса отправляется на сервер, анализируется, а заполнитель и информация результата возвращается клиенту. Это вы получаете при настройке useServerPrepStmts=true
. Строка оператора только один раз отправляется на сервер с вызовом COM_STMT_PREPARE
(документировано здесь). Каждое выполнение выполняется путем отправки COM_STMT_EXECUTE
с подготовленным дескриптором оператора и буквальными значениями для замены заполнителей.
В отличие от подготовленного клиента, мы можем использовать аналогичный блок кода (но на этот раз с включенными подготовленными операциями):
ps2=conn2.prepareStatement("select ?")
ps2.setInt(1, 42)
ps2.executeQuery()
ps2.setInt(1, 43)
ps2.executeQuery()
И журнал покажет:
254 Prepare select ?
254 Execute select 42
254 Execute select 43
Вы можете видеть, что оператор готов к выполнению. Журнал делает нам одолжение и показывает полную инструкцию для выполнения, но на самом деле для каждого исполнения отправляются только значения заполнителя от клиента к серверу.
Кэширование подготовленных заявлений
Многие пулы подключений будут кэшировать подготовленные инструкции через использование соединения, что означает, что если вы вызываете conn.prepareStatement("select ?")
, он будет возвращать тот же экземпляр PreparedStatement
при последовательных вызовах с той же строкой оператора. Это полезно, чтобы избежать повторной подготовки той же строки на сервере, когда соединения возвращаются в пул между транзакциями.
Параметр MySQL JDBC cachePrepStmts
будет кэшировать подготовленные операторы таким образом (как подготовленные как клиентские, так и серверные операторы), а также кэшировать "готовность" к заявлению. В MySQL есть некоторые утверждения, которые не подготавливаются на стороне сервера. Драйвер попытается подготовить отчет на сервере, если он считает, что это возможно, и, если подготовка не удалась, вернитесь к подготовленному клиентом оператору. Эта проверка является дорогостоящей из-за необходимости совершить кругосветное путешествие на сервер. Опция также кэширует результат этой проверки.
Надеюсь, что это поможет.