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
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:
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:
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:
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!
Leave a Reply