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

October 12, 2015 by Mauda Leave a Comment

Conteúdo do Post:
  1. Criando a classe NamedParameterStatement – Construtores
  2. interface java.sql.Connection
  3. finnaly{

Olá Pessoal, tudo bom?

O artigo de hoje é a terceira 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 – Construtores

Agora iremos realizar a construção da classe NamedParameterStatement. Nessa classe é que estará localizado o parser construído na segunda parte deste artigo. Mas antes de começarmos a construção dessa classe, vamos explorar como é que a interface java.sql.Connection realiza a instanciação de um objeto PreparedStatement. Isso é muito importante para que possamos entender quais são os contextos existentes para a invocação de nossa classe, visto que existem muitas formas de construir uma query SQL.

interface java.sql.Connection

A interface java.sql.Connection ((API java.sql.Connection – JDK 8 – http://docs.oracle.com/javase/8/docs/api/java/sql/Connection.html)) possui métodos para obter os três tipos básicos de Statements do JDBC:

  • Statement ((API java.sql.Statement – JDK 8 – http://docs.oracle.com/javase/8/docs/api/java/sql/Statement.html))
  • PreparedStatement ((API java.sql.PreparedStatement – JDK 8 – http://docs.oracle.com/javase/8/docs/api/java/sql/PreparedStatement.html))
  • CallableStatement ((API java.sql.PreparedStatement – JDK 8 – http://docs.oracle.com/javase/8/docs/api/java/sql/CallableStatement.html))

Nesse artigo nós iremos focar na parte da obtenção do PreparedStatement. Para essa interface existem seis métodos que realizam esse trabalho:

  • PreparedStatement prepareStatement(String sql)
  • PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
  • PreparedStatement prepareStatement(String sql, int[] columnIndexes)
  • PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
  • PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
  • PreparedStatement prepareStatement(String sql, String[] columnNames)

Para a construção dessa nossa classe iremos apenas trabalhar com os dois primeiros métodos. Estes dois métodos realizam o que nós pretendemos fazer dentro da nossa classe. O primeiro método irá trabalhar com queries que não possuem o conceito de auto generated, ou seja, que não realizam a geração automática de valores para as primary keys. Já o segundo método irá trabalhar justamente com esse tipo de Query, que se utiliza de geração automática de valores.

Assim devemos ter em mente que a nossa classe irá gerar uma instância de PreparedStatement a partir de um desses dois métodos. Nesse contexto é necessário que a nossa classe possua um atributo interno que armazene essa instância gerada. Outro detalhe é que para manter a classe genérica devemos passar via construtor da nossa classe a classe Connection necessária para obtermos a instância.

Vamos explicitar isso em código. Abaixo segue o código com os dois construtores que utilizarão os métodos mencionados acima. Ambos fazem o mesmo trabalho que é realizar uma transformação do namedSQL em positionSQL e depois obter a instância do PreparedStatement.

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

finnaly{

Nesse momento nós já possuímos uma forma de criar instâncias da classe NamedParameterStatement, mas ainda não podemos atribuir diretamente os valores, visto que não existe uma forma de iteração com a instância de PreparedStatament criada. Essa iteração será desenvolvida na próxima parte desse artigo!

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