Primeiro, é importante distinguir entre as instruções preparadas pelo cliente e pelo servidor.
Declarações preparadas pelo cliente
As declarações preparadas pelo cliente são declarações preparadas "emuladas". Isso significa que a string da instrução SQL é tokenizada no lado do cliente e quaisquer espaços reservados são substituídos por valores literais antes de enviar a instrução ao servidor para execução. Uma instrução SQL completa é enviada ao servidor em cada execução. Você pode usar o log geral para investigar como isso funciona. por exemplo.
o seguinte código:
ps=conn.prepareStatement("select ?")
ps.setInt(1, 42)
ps.executeQuery()
ps.setInt(1, 43)
ps.executeQuery()
mostraria no log:
255 Query select 42
255 Query select 43
A "consulta" indica que, no nível do protocolo, um
COM_QUERY
O comando é enviado com a string de instrução a seguir. Declarações preparadas pelo servidor
As instruções preparadas pelo servidor são instruções preparadas "verdadeiras", o que significa que o texto da consulta é enviado para o servidor, analisado e reservado, e as informações do resultado são retornadas ao cliente. Isso é o que você obtém ao definir
useServerPrepStmts=true
. A string de instrução só é enviada ao servidor uma vez com um COM_STMT_PREPARE
call (documentado aqui
). Cada execução é realizada enviando um COM_STMT_EXECUTE
com o identificador de instrução preparado e os valores literais para substituir os espaços reservados. Para contrastar com o exemplo preparado pelo cliente, podemos usar um bloco de código semelhante (mas desta vez com instruções preparadas pelo servidor habilitadas):
ps2=conn2.prepareStatement("select ?")
ps2.setInt(1, 42)
ps2.executeQuery()
ps2.setInt(1, 43)
ps2.executeQuery()
E o log mostraria:
254 Prepare select ?
254 Execute select 42
254 Execute select 43
Você pode ver que a instrução é preparada antes de ser executada. O log está nos fazendo um favor e mostrando a instrução completa para a execução, mas, na verdade, apenas os valores do placeholder são enviados do cliente para o servidor para cada execução.
Armazenamento de Declarações Preparadas em Cache
Muitos pools de conexão armazenarão em cache as instruções preparadas nos usos de uma conexão, o que significa que, se você chamar
conn.prepareStatement("select ?")
, ele retornará o mesmo PreparedStatement
instância em chamadas sucessivas com a mesma string de instrução. Isso é útil para evitar preparar a mesma string no servidor repetidamente quando as conexões são retornadas ao pool entre transações. A opção MySQL JDBC
cachePrepStmts
armazenará em cache as instruções preparadas dessa maneira (tanto as instruções preparadas pelo cliente quanto pelo servidor), bem como armazenará em cache a "preparabilidade" de uma instrução. Existem algumas instruções no MySQL que não são preparáveis no lado do servidor. O driver tentará preparar uma instrução no servidor se acreditar que é possível e, se a preparação falhar, retornará a uma instrução preparada pelo cliente. Essa verificação é cara devido à necessidade de uma viagem de ida e volta ao servidor. A opção também armazenará em cache o resultado dessa verificação. Espero que isto ajude.