• Skip to primary navigation
  • Skip to content

Mauda

IT, Java and Music

Graduação   SCJP   Mestrado
  • Apresentação
  • Certificação Java
  • JPA
    • Exceptions
  • JSF
  • Versionamento
  • Contato

SQL – Named Parameters for PreparedStatement – Parte V

October 26, 2015 by Mauda Leave a Comment

Conteúdo do Post:
  1. Criando a classe NamedParameterStatement – Execução
  2. Chaves Geradas Automaticamente pelo Banco
  3. Casualidades…
  4. Código Final da classe NamedParameterStatement
  5. finnaly{

Olá Pessoal, tudo bom?

O artigo de hoje é a quinta parte de uma adaptação do artigo de Adam Crume criado em 03 de abril de 2007 para o site Java World (link).

Para essa adaptação eu modifiquei um pouco o código apresentado inserindo o conceito de generics e algumas melhorias no código. Veja abaixo como ficou o resultado.

Criando a classe NamedParameterStatement – Execução

Dentro do mundo SQL podemos agrupar todos os comandos SQL em três grupos distintos:

  • DML – Data Manipulation Language
  • DDL – Data Definition Language
  • DCL – Data Control Language

A Figura 1 ilustra quais são os comandos SQL que pertencem a cada tipo de grupo caso você não lembre o que cada um faz

Figura 01 – Grupos SQL e seus comandos básicos

Dentro da biblioteca do JDBC existem três métodos dentro da interface Statement que servem para a execução de comandos SQL:

  • execute(String) ((Java API – Método execute() da interface Statement – http://docs.oracle.com/javase/8/docs/api/java/sql/Statement.html#execute-java.lang.String-))
  • executeQuery(String) ((Java API – Método executeQuery() da interface Statement – http://docs.oracle.com/javase/8/docs/api/java/sql/Statement.html#executeQuery-java.lang.String-))
  • executeUpdate(String) ((Java API – Método executeUpdate() da interface Statement – http://docs.oracle.com/javase/8/docs/api/java/sql/Statement.html#executeUpdate-java.lang.String-))

Iremos criar para cada um desses métodos da Statement, métodos iguais que chamam esses métodos, no formato abaixo:

Java
1
2
3
public ResultSet executeQuery() throws SQLException {
return statement.executeQuery();
}

O código completo dos outros dois métodos está no código final da classe mais abaixo.

Chaves Geradas Automaticamente pelo Banco

Outro aspecto importante a ser discutido é sobre a recuperação de chaves primárias geradas pelo banco de dados. Assim como existe um construtor que passamos uma constante para recuperar essas chaves, temos que ter uma forma de acessar a instância de PreparedStatement interno e recuperar realmente esses valores.

Para recuperar esses valores nós utilizamos o método getGeneratedKeys() ((Java API – Método getGeneratedKeys() da interface Statement – http://docs.oracle.com/javase/8/docs/api/java/sql/Statement.html#getGeneratedKeys–)) da interface Statement. Esse método retorna um ResultSet com os valores gerados para cada coluna que compõem a primary key da tabela.

Esse método também necessita possuir uma implementação dentro da nossa classe. Ficará como no padrão dos métodos de execução apenas chamando o método da classe Statement, como mostra o código abaixo:

Java
1
2
3
public ResultSet getGeneratedKeys() throws SQLException {
return statement.getGeneratedKeys();
}

Casualidades…

Para finalizar o código de nossa classe, vamos criar um método para obter a instância interna de PreparedStatement e outro método para realizar o fechamento desse statement.

Código Final da classe NamedParameterStatement

Abaixo segue o código final da classe NamedParameterStatement:

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
 
public class NamedParameterStatement {
////////////////////////////////////////////////////////////////
// ATRIBUTOS
////////////////////////////////////////////////////////////////
//Cria um PreparedStatement interno para realizar a execucao do SQL
private PreparedStatement statement;
 
//Map para indicar as posicoes dos parametros
private final Map<String, List<Integer>> mapPosicoesParametros = new HashMap<String, List<Integer>>();
 
////////////////////////////////////////////////////////////////
// CONSTRUTORES
////////////////////////////////////////////////////////////////
/**
* Construtor que realiza a instanciacao de um prepareStatement a partir da connection
* @param connection - A conexao com o banco de dados
* @param query - A query no formato namedQuery
* @throws SQLException - Se o statement nao puder ser criado
*/
public NamedParameterStatement(Connection connection, String namedQuery) throws SQLException {
String parsedQuery = parse(namedQuery);
statement = connection.prepareStatement(parsedQuery);
}
 
/**
* Construtor que realiza a instanciacao de um prepareStatement a partir da connection para inserts com auto generated keys
* @param connection - A conexao com o banco de dados
* @param query - A query no formato namedQuery
* @param RETURN_GENERATED_KEYS - A constante definida em java.sql.Statement.RETURN_GENERATED_KEYS
* @throws SQLException - Se o statement nao puder ser criado
* Construtor que realiza a instanciacao de um prepareStatement a partir da connection
* @param connection the database connection
* @param query   the parameterized query
* @throws SQLException if the statement could not be created
*/
public NamedParameterStatement(Connection connection, String namedQuery, Integer RETURN_GENERATED_KEYS) throws SQLException {
String parsedQuery = parse(namedQuery);
statement = connection.prepareStatement(parsedQuery, RETURN_GENERATED_KEYS);
}
 
////////////////////////////////////////////////////////////////
// PARSER
////////////////////////////////////////////////////////////////
 
private String parse(String namedQuery) {
int length = namedQuery.length();
 
//Cria um String Buffer com o tamanho do SQL
StringBuilder parsedQuery = new StringBuilder(length);
 
boolean inSingleQuote = false;
boolean inDoubleQuote = false;
 
int position = 1;
//Percorre todo o SQL
for(int i = 0; i < length; i++) {
char c = namedQuery.charAt(i);
//: Significa inicio de um rotulo de parametro
//E nao esta em uma palavra com aspas simples ou duplas
if(c == ':' && !inSingleQuote && !inDoubleQuote && i+1 < length &&
Character.isJavaIdentifierStart(namedQuery.charAt(i+1))) {
int j = i+2;
while(j < length && Character.isJavaIdentifierPart(namedQuery.charAt(j))) {
j++;
}
String name = namedQuery.substring(i+1, j);
c='?'; // substitui o caracter c pelo parametro de index
i += name.length(); // pula i ate o fim do nome do parametro
 
List<Integer> indexList = mapPosicoesParametros.get(name);
//Se o parametro ainda nao existir no map inicializa-o
if(indexList == null) {
indexList = new LinkedList<Integer>();
mapPosicoesParametros.put(name, indexList);
}
indexList.add(position++);
}
//Adiciona o novo caractere a query passada pelo parser
parsedQuery.append(c);
if(c == '\'') {
inSingleQuote = !inSingleQuote;
} else if(c == '"') {
inDoubleQuote = !inDoubleQuote;
}
}
return parsedQuery.toString();
}//Fim do metodo parser
////////////////////////////////////////////////////////////////
// PARAMETERS
////////////////////////////////////////////////////////////////
/**
* Returns the indexes for a parameter.
* @param name parameter name
* @return parameter indexes
* @throws IllegalArgumentException if the parameter does not exist
*/
private List<Integer> getIndexes(String name) {
List<Integer> indexes = mapPosicoesParametros.get(name);
if(indexes == null) {
throw new IllegalArgumentException("Parameter not found: " + name);
}
return indexes;
}
/**
* Sets a parameter.
* @param name  parameter name
* @param value parameter value
* @throws SQLException if an error occurred
* @throws IllegalArgumentException if the parameter does not exist
* @see PreparedStatement#setBoolean(int, boolean)
*/
    public void setBoolean(String name, boolean value) throws SQLException {
        for(Integer position : getIndexes(name)){
statement.setBoolean(position, value);
}
    }
/**
* Sets a parameter.
* @param name  parameter name
* @param value parameter value
* @throws SQLException if an error occurred
* @throws IllegalArgumentException if the parameter does not exist
* @see PreparedStatement#setDate(int, java.sql.Date)
*/
    public void setDate(String name, Date value) throws SQLException {
        for(Integer position : getIndexes(name)){
statement.setDate(position, value);
}
    }
/**
* Sets a parameter.
* @param name  parameter name
* @param value parameter value
* @throws SQLException if an error occurred
* @throws IllegalArgumentException if the parameter does not exist
* @see PreparedStatement#setDouble(int, double)
*/
    public void setDouble(String name, double value) throws SQLException {
        for(Integer position : getIndexes(name)){
statement.setDouble(position, value);
}
    }
 
/**
     * Sets a parameter.
     * @param name  parameter name
     * @param value parameter value
     * @throws SQLException if an error occurred
     * @throws IllegalArgumentException if the parameter does not exist
     * @see PreparedStatement#setInt(int, int)
     */
    public void setInt(String name, int value) throws SQLException {
        for(Integer position : getIndexes(name)){
statement.setInt(position, value);
}
    }
/**
     * Sets a parameter.
     * @param name  parameter name
     * @param value parameter value
     * @throws SQLException if an error occurred
     * @throws IllegalArgumentException if the parameter does not exist
     * @see PreparedStatement#setInt(int, int)
     */
    public void setLong(String name, long value) throws SQLException {
        for(Integer position : getIndexes(name)){
statement.setLong(position, value);
}
    }
/**
* Sets a parameter.
* @param name  parameter name
* @param value parameter value
* @throws SQLException if an error occurred
* @throws IllegalArgumentException if the parameter does not exist
* @see PreparedStatement#setObject(int, java.lang.Object)
*/
private void setObject(String name, Object value) throws SQLException {
for(Integer position : getIndexes(name)){
statement.setObject(position, value);
}
}
/**
     * Sets a parameter.
     * @param name  parameter name
     * @param value parameter value
     * @throws SQLException if an error occurred
     * @throws IllegalArgumentException if the parameter does not exist
     * @see PreparedStatement#setString(int, java.lang.String)
     */
    public void setString(String name, String value) throws SQLException {
        for(Integer position : getIndexes(name)){
statement.setString(position, value);
}
    }
/**
     * Sets a parameter.
     * @param name  parameter name
     * @param value parameter value
     * @throws SQLException if an error occurred
     * @throws IllegalArgumentException if the parameter does not exist
     * @see PreparedStatement#setTimestamp(int, java.sql.Time)
     */
    public void setTime(String name, Time value) throws SQLException {
        for(Integer position : getIndexes(name)){
statement.setTime(position, value);
}
    }
 
/**
     * Sets a parameter.
     * @param name  parameter name
     * @param value parameter value
     * @throws SQLException if an error occurred
     * @throws IllegalArgumentException if the parameter does not exist
     * @see PreparedStatement#setTimestamp(int, java.sql.Timestamp)
     */
    public void setTimestamp(String name, Timestamp value) throws SQLException {
        for(Integer position : getIndexes(name)){
statement.setTimestamp(position, value);
}
    }
////////////////////////////////////////////////////////////////
// EXECUCAO DE QUERIES
////////////////////////////////////////////////////////////////
/**
     * Executes the statement.
     * @return true if the first result is a {@link ResultSet}
     * @throws SQLException if an error occurred
     * @see PreparedStatement#execute()
     */
    public boolean execute() throws SQLException {
        return statement.execute();
    }
/**
     * Executes the statement, which must be a query.
     * @return the query results
     * @throws SQLException if an error occurred
     * @see PreparedStatement#executeQuery()
     */
    public ResultSet executeQuery() throws SQLException {
        return statement.executeQuery();
    }
/**
     * Executes the statement, which must be an SQL INSERT, UPDATE or DELETE statement;
     * or an SQL statement that returns nothing, such as a DDL statement.
     * @return number of rows affected
     * @throws SQLException if an error occurred
     * @see PreparedStatement#executeUpdate()
     */
    public int executeUpdate() throws SQLException {
        return statement.executeUpdate();
    }
////////////////////////////////////////////////////////////////
// RECUPERACAO DE CHAVES GERADAS
////////////////////////////////////////////////////////////////
/**
     * Retrieves any auto-generated keys created as a result of executing this
* Statement object. If this Statement object did not generate any keys,
* an empty ResultSet object is returned.
     * @return a ResultSet object containing the auto-generated key(s)
* generated by the execution of this Statement object
     * @throws SQLException if an error occurred
     * @see PreparedStatement#getGeneratedKeys()
     */
public ResultSet getGeneratedKeys() throws SQLException {
return statement.getGeneratedKeys();
}
////////////////////////////////////////////////////////////////
// OUTROS
////////////////////////////////////////////////////////////////
/**
     * Returns the underlying statement.
     * @return the statement
     */
    public PreparedStatement getStatement() {
        return statement;
    }
/**
     * Closes the statement.
     * @throws SQLException if an error occurred
     * @see Statement#close()
     */
    public void close() throws SQLException {
        statement.close();
    }
}//Fim da classe<span class="pun">;</span>

finnaly{

Assim terminamos a criação de uma classe que utiliza labels ao invés de positions para realizar execuções de SQL. Espero que você tenha apreciado a dissecação da classe explicando brevemente alguns pontos relacionados para a sua criação.

Em um artigo futuro iremos criar um exemplo de utilização desta classe.

Duvidas ou sugestões? Deixe seu feedback! Isso ajuda a saber a sua opinião sobre os artigos e melhorá-los para o futuro! Isso é muito importante!

Até um próximo post!

Filed Under: Java, JDBC Tagged With: Java, JDBC, PreparedStatement, SQL

About Mauda

Mestre em Informática, Analista de Sistemas, Professor, SCJP e Baterista. Desde 2002 trabalhando no mundo Java e ensinando pessoas sobre desenvolvimento de sistemas. Mais informações

Reader Interactions

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Advertisements

Copyright © 2022 · Genesis Framework · WordPress · Log in