• 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 IV

October 19, 2015 by Mauda Leave a Comment

Conteúdo do Post:
  1. Criando a classe NamedParameterStatement – SetParameters
  2. finnaly{

Olá Pessoal, tudo bom?

O artigo de hoje é a quarta 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 – SetParameters

De acordo com a ultima parte, nós criamos os construtores necessários para criar uma instância da classe NamedParameterStatement. Dentro desses construtores nós realizávamos as atividades de parser do namedSQL, transformando para positionalSQL e a criação de PreparedStatement interno. Seguindo o padrão de métodos JDBC nesse momento é necessário atribuirmos os parâmetros para a query criada.

Assim será melhor criarmos um método que retorne o PreparedStatement interno da classe e dessa forma atribuiremos os parâmetros a essa SQL? Pense que não sabemos quais são as posições dos parâmetros, temos conhecimento apenas dos labels que utilizamos para criar a namedSQL. Dessa forma, a única coisa a ser feita será criarmos métodos em que podemos setar os parâmetros necessários a nossa Query.

Se observarmos a API da PreparedStatement ((API java.sql.PreparedStatement – JDK 8 – http://docs.oracle.com/javase/8/docs/api/java/sql/PreparedStatement.html)) podemos perceber que existe uma gama muito grande de métodos set, como setBoolean, setDate, setDouble, setInt, setString. A maioria desses métodos segue o padrão de possuir dois parâmetros. O primeiro é a posição que o ponto de interrogação se encontra no SQL (perguntinha, começa em 0 ou 1????) e o segundo é a informação do tipo correspondente que queremos setar.

Para a nossa classe iremos seguir o mesmo conceito, ou seja o primeiro parâmetro será a posição e o segundo a informação. Somente que aqui, não iremos passar um int com a posição, mas iremos passar uma String com o label. Assim um esqueleto inicial do método seria o seguinte:

Java
1
2
3
public void setInt(String name, int value) throws SQLException {
//alguma coisa aqui
}

Agora o que irá dentro do nosso método? O primeiro ponto a ser pensado é que nós precisamos setar esse valor passado no preparedStatement interno. Assim de alguma forma é necessário obter as posições que esse label se encontrava no SQL. Para isso vamos relembrar o nosso parser.

Em um determinado ponto, linhas 80 a 86, quando encontrávamos um label, este era armazenado em um Map, mapPosicoesParametros, juntamente com a posição naquele momento do parser. Será esse map que trará a informação das posições de um determinado label. Como vamos utilizar isso em vários métodos de set, vamos criar um método a parte para realizar essa atividade. O código abaixo possui as informações para realizar essa tarefa:

Java
1
2
3
4
5
6
7
private List<Integer> getIndexes(String name) {
List<Integer> indexes = mapPosicoesParametros.get(name);
if(indexes == null) {
throw new IllegalArgumentException("Parameter not found: " + name);
}
return indexes;
}

Lembre-se, estamos trabalhando com um Map, logo o próprio label é a key para uma determinada posição. Caso a lista retornada seja nula, isso significa que aquele label nunca esteve presente no SQL, dessa forma retornaremos uma Exception indicando que não foi possível achar o parâmetro.

Bom, com o método retornando uma lista de posições, somos obrigados a trabalhar com uma estrutura de repetição. Para ficar mais claro vamos utilizar a estrutura de for each, por ser semanticamente mais fácil de ler. E além disso já teremos a posição para inserir o valor como parâmetro no PreparedStatement. Assim o nosso código ficará da seguinte forma:

Java
1
2
3
4
5
public void setInt(String name, int value) throws SQLException {
for(Integer position : getIndexes(name)){
statement.setInt(position, value);
}
}

Para os métodos set de outros tipos iremos seguir o mesmo padrão, realizando apenas a mudança das informações referentes ao tipo. Como forma de ilustrar aqui o exemplo iremos criar apenas alguns métodos set, sendo estes os mais comuns. Caso você necessite de outros métodos fique a vontade para criar de acordo com a sua necessidade, bastando verificar quais são os métodos existentes dentro da API do PreparedStatement.

Iremos criar os métodos set para os tipos Boolean, Date, Double, Int, Long, Object, String, Time e TimeStamp. Maiores detalhes você confere no código inteiro da classe até essa parte que está abaixo.

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
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);
}
    }
}//Fim da classe

finnaly{

Na próxima parte desse artigo iremos ver o código necessário para a execução da nossa classe. Está terminando!! 🙂

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 © 2025 · Genesis Framework · WordPress · Log in