Title: PROGRAMA
1PROGRAMAÇÃO DISTRIBUÍDA EM JAVAVerão/2001
- Aula 10
- API JDBC
- 09.02.2001
- Luciano Silva
- e-mail lucianos_at_ime.usp.br
1
2Tópicos da Aula 10
- API JDBC
- Arquitetura das camadas JDBC
- Classes principais de java.sql
- Abertura e fechamento de conexões
- Consulta simples
- Métodos para acessos a dados de registros
- Consultas parametrizadas
- Stored Procedures
- Transações
3API JDBC (I)
- A API JDBC (Java Database Connectivity)
disponibiliza para aplicações Java uma interface
para acessar bancos de dados baseados em SQL. - Do ponto de vista das aplicações, o programador
somente precisa se preocupar com detalhes de alto
nível com o servidor de banco de dados.
4API JDBC (II)
- A API JDBC funciona num nível denominado call
level ( nível de chamada ). Isto significa que
as aplicações invocam consultas SQL, estas são
passadas para o servidor de BD, executadas e
resultados são devolvidos para a aplicação.
5API JDBC (III)
- O único trabalho da aplicação é
- 1. Abrir conexão com o servidor de BD
- 2. Construir uma consulta SQL ou chamada para
stored procedure usando classes da API - 3. Solicitar a execução
- 4. Receber e utilizar os dados
- 5. Fechar a conexão
6API JDBC (IV)
- Todos os detalhes de comunicação de baixo nível
com o servidor de BD é feito através de classes
especiais chamadas driver classes, ou
simplesmente, drivers. - Existe uma grande variedade de drivers já
disponibilizados para JDBC. Existe, ainda, a
possibilidade de se construir novos drivers a
partir de classes e interfaces da API.
7Por que usar JDBC ?
- 1. Facilidade de manutenção
- 2.Conectividade com ampla gama de servidores de
BD - 3. Portabilidade
- 4. Prototipação rápida
8Cenários de uso de JDBC
- Existe uma série de sistemas, principalmente
aqueles implementados em Java e em C/C, onde o
uso de JBDC está se tornando constante. Com Java,
constrói-se interfaces portáveis para os clientes
e são incorporados nestas interfaces mecanismos
para acesso bastante simplificado a banco de
dados.
9Cenário (I) - Applets
10Cenário (II) - Aplicações Desktop
11Cenário (III) - Aplicações Multi-tier
12Arquitetura JDBC
13Estrutura da API JDBC
- As classes da API JDBC utilizadas pelas
aplicações estão concentradas em dois pacotes - java.sql.
- javax.sql.
14Algumas classes básicas do pacote java.sql
- Existem quatro classes abstratas básicas muito
utilizadas - DriverManager
- Connection
- Statement
- ResultSet
15Relação entre as classes
16Classe DriverManager
- Esta classe é responsável por
- manipular o carregamento de drivers
- providenciar suporte para criação de novas
conexões
17Classe Connection
- Representa uma conexão com um banco de dados
particular. - A partir de Connection pode-se
- criar consultas
- criar consultas parametrizadas
- criar chamadas para stored procedures
- encerrar uma conexão
-
18Classe Statement
- Age como um container para executar uma consulta
SQL para uma determinada conexão. - Para consultas mais complicadas ( consultas
parametrizadas) ou invocação de stored
procedures, são utilizadas classes mais
específicas que Statement ( PreparedStatement e
CallableStatement). -
19Classe ResultSet
- Controla o acesso aos registros resultantes de
uma consulta via Statement, PreparedStatement ou
CallableStatement. - Possui métodos para navegar nos registros de
resultados, como também consultar dados destes
registros. -
20Outras classes e interfaces do pacotes
- No pacote java.sql. existe uma série de outras
classes, interfaces e subpacotes que permitem,
por exemplo, construir classes do tipo driver
para acesso específico. -
21Abrindo conexões (I)
- Existe uma série de detalhes envolvidos na
abertura de conexão com um servidor de BD que
devem ser providenciados pela aplicação. - Para estas providências, geralmente são
utilizadas as classes Drivermanager(java.sql) e
Class(java.lang). -
22Abrindo conexões (II)
- Detalhes que precisam ser providenciados
- 1. Especificar URL de acesso com protocolos de
banco de dados adequados - 2. Especificar parâmetros de conexão, tais como
nome do usuário e senha - 3. Registrar drivers para uso da aplicação
-
23URL de acesso ao servidor de BD
- A sintaxe mais utilizada para acessar um servidor
de banco de dados é a seguinte - jdbcltsubprotocologtltsubnomegt
- onde subprotocolo significa o protocolo do driver
e subnome geralmente indica servidor, porta e
banco de dados. -
24Exemplos de URL de acesso
- jdbcodbcfred
- subprotocolo odbc
- fonte de dados fred
- jdbcdbnet//wombat356/fred
- subprotocolodbnet
- servidor wombat
- porta 356
- fonte de dados fred
-
25Argumentos para URL de acesso
- Em algumas situações, parâmetros de conexão tais
como usuário e senha são necessários. Neste caso,
utiliza-se os nomes dos parâmetros juntamente com
seus respectivos valores. - Cada par parâmetro-valor é separado por um
ponto-e-vírgula () -
26Exemplos
- jdbcodbcwombatCacheSize20
- Parâmetro de tamanho de cache
- jdbcodbcqeoraUIDkghPWDfooey
- parâmetro UID ( Identificação )
- parâmetro PWD ( Senha )
-
27Registro de drivers
- A camada de gerenciamento do JDBC precisa saber
quais os drivers de banco de dados estão
disponibilizados. - A maneira mais simples de executar tal tarefa é
carregar explicitamente os drivers a serem
utilizados, valendo-se do método forName da
classe Class ( pacote java.lang ). -
28Exemplo
- Para carregar, por exemplo, o driver chamado
acme.db.Driver, utiliza-se - Class.forName("acme.db.Driver")
- Para carregar, o driver da ponte JDBC-ODBC
utiliza-se - Class.forName(jdbc.odbc.JdbcOdbcDriver")
-
29Considerações sobre carregamento de drivers
- Os drivers são carregados antes de serem
estabelecidas as conexões - A priori, podem ser carregados quantos drivers
forem necessários para a aplicação. -
30Considerações sobre carregamento de drivers
- Os drivers são carregados antes de serem
estabelecidas as conexões - A priori, podem ser carregados quantos drivers
forem necessários para a aplicação. -
31Exemplo completo - Abertura/fechamento da conexão
- import java.net.URL
- import java.sql.
- class exemplo
- public static void main(String argv)
- try
- String url "jdbcodbcwombat"
- Class.forName(jdbc.odbc.JdbcOdbcDr
iver) - Connection con DriverManager.getConnection(ur
l, "kgh", "") - con.close()
-
- catch (Exception ex)
- ex.printStackTrace()
-
-
-
32Executando consultas simples...
- Para se executar consultas simples são
utilizados os seguintes passos - 1. Cria-se um Statement com base na conexão
- 2. Chama-se o método executeQuery do Statement
com a consulta SQL, devolvendo o resultado numa
instância de ResultSet -
33Qual especificação do SQL pode-se utilizar?
- A priori, espera-se que o servidor de BD
suporte, pelo menos, o padrão ANSI SQL 92, que é
bastante abrangente para a maioria das
aplicações. - Se o servidor suporta construções específicas,
tais como consultas com SQL temporal, a cláusula
por ser enviada sem problemas como parâmetro do
método executeQuery. -
34Exemplo consulta
- ...
- Connection con DriverManager.getConnection(
url, "kgh", "") - // Cria-se Statement com base na conexão con
- Statement stmt con.createStatement()
- // Executa-se a consulta dos campos a,b,c da
table1 - ResultSet r stmt.executeQuery("SELECT a,
b, c FROM -
Table1") - ...
-
-
35Como navegar no resultado ?
- A partir do objeto ResultSet pode-se
- verificar se existem mais registros para serem
lidos, com o método next() - pode-se consultar os campos através de métodos
específicos, que mapeam o tipo SQL para o tipo
Java. Por exemplo, getString(campo) obtém um
campo do tipo string. -
36Exemplo
- ...
- Connection con DriverManager.getConnection(
url, "kgh", "") - // Cria-se Statement com base na conexão con
- Statement stmt con.createStatement()
- // Executa-se a consulta dos campos a,b,c da
table1 - ResultSet r stmt.executeQuery("SELECT a,
b, c FROM -
Table1") - while (r.next())
- int i r.getInt("a")
- String s r.getString("b")
- byte b r.getBytes("c")
- System.out.println("ROW " i " "
s " " b0) -
- ...
-
37Objeto ResultSet revisitado
- A partir do objeto ResultSet pode-se
- verificar se existem mais registros para serem
lidos, com o método next() - pode-se consultar os campos através de métodos
específicos, que mapeam o tipo SQL para o tipo
Java. Por exemplo, getString(campo) obtém um
campo do tipo string. -
38Exemplo
- ...
- Connection con DriverManager.getConnection(
url, "kgh", "") - // Cria-se Statement com base na conexão con
- Statement stmt con.createStatement()
- // Executa-se a consulta dos campos a,b,c da
table1 - ResultSet r stmt.executeQuery("SELECT a,
b, c FROM -
Table1") - while (r.next())
- int i r.getInt("a")
- String s r.getString("b")
- byte b r.getBytes("c")
- System.out.println("ROW " i " "
s " " b0) -
- ...
-
39Métodos para obtenção dos dados
- O primeiro problema de se usar um objeto
ResultSet é descobrir qual método utilizar para
obter determinado campo do conjunto resultado da
consulta. - Para grande parte dos tipos de dados existem
algumas possibilidades múltiplas para consulta,
embora algumas sejam recomendadas. -
40Tabela de métodos por tipo (I)
x - funciona X -
recomendado
41Tabela de métodos por tipo (II)
x - funciona X -
recomendado
42Tabela de métodos por tipo (III)
x - funciona X -
recomendado
43Obtenção de Large Objects (LOB)
- Em algumas situações, os métodos anteriores não
são suficientes para obter grandes objetos numa
linha, tais como objetos BLOB ( Binary Large
Object) ou CLOB ( Character Large Object). - Objetos ResultSet disponibilizam métodos de
leitura de objetos de tal tipo, disponibilizando
streams de entrada. -
44Métodos para leitura de LOB
- São disponibilizados três métodos
- getBinaryStream() para leitura de objetos
binários - getAsciiStream() para leitura de caracteres
ASCII - getUnicodeStream() para leitura de caracteres
Unicode -
45Exemplo
- Statement stmt con.createStatement()
- ResultSet r stmt.executeQuery("SELECT x FROM
Table2") - byte buff new byte4096
- while (r.next())
- InputStream fin r.getAsciiStream(1)
- for ()
- int size fin.read(buff)
- if (size -1) // Se chegou no final
do objeto - break
-
- ... Processa parte do objeto lido em buff
-
-
-
-
46Valores NULL (I)
- Valores de registros com NULL podem aparecer
numa tabela de banco de dados. - NULL é aplicado principalmente em
- quando o campo não se aplica ao registro
- quando o valor do campo para o registro é
desconhecido -
47Valores NULL (II)
- Quando se invoca um método de obtenção do tipo
get(campo) e o campo contém NULL, o resultado
depende do método invocado - null retornado por métodos que devolvem
objetos Java (getString, getBigDecimal, getBytes,
getDate, getTime, getTimestamp, getAsciiStream,
getUnicodeStream , getBinaryStream , getObject) -
48Valores NULL (III)
- 0 retornado por métodos de devolvem valores
numéricos (getByte, getShort, getInt, getLong,
getFloat, and getDouble) - false retornado pelo método de consulta de
valores booleanos getBoolean. -
49Classe PreparedStatement (I)
- A classe PreparedStatement é uma classe derivada
de Statement. - Prepared Statement representa uma cláusula SQL de
forma pré-compilada, cuja execução pode ser mais
rápida que cláusulas SQL construídas com
Statement. - Cláusulas usadas constantemente geralmente são
construídas com PreparedStatement ao invés de
Statement. -
50Classe PreparedStatement (II)
- PreparedStatement é usada em duas situações
- deixar a cláusula SQL pré-compilada
- permitir a definição de parâmetros da consulta
em tempo de execução ( consultas parametrizadas
). Os parâmetros de uma consulta recebem o nome
técnico de parâmetros IN. -
51Classe PreparedStatement (III)
- A utilização de PreparedStament é análoga à da
classe Statement - 1. Com base em uma conexão, cria-se uma
instância de PreparedStatement - 2. Chama-se o método de execução adequado
- 3. Obtém-se os resultados em ResultSet, caso
necessário -
52Consultas parametrizadas
- Para construir consultas parametrizadas,
utiliza-se o sinal ? dentro da cláusula SQL usada
na criação de PreparedStatement. - Os parâmetros recebem uma numeração sequencial
(1,2,3,...). O número associado a um parâmetro é
utilizado posteriormente para associar valores
para a execução da cláusula SQL. -
53Exemplo
- Supondo que já exista uma conexão aberta com,
abaixo tem-se uma consulta SQL do tipo update,
dependendo de dois parâmetros - PreparedStatement pstmt con.prepareStatement(
"UPDATE table4 SET m ? WHERE x ?") -
54Como atribuir valores aos parâmetros ?
- Valores são atribuídos aos parâmetros
utilizando-se métodos do tipo set(ordem do
parâmetro, valor). - Estes métodos são invocados a partir do objeto
PreparedStatement criado.
55Exemplo
- ...
- PreparedStatement pstmt con.prepareStatement(
"UPDATE table4 SET m ? WHERE x ?") - pstmt.setLong(1, 123456789)
- pstmt.setLong(2, 100000000)
- ...
-
-
56Como executar uma PreparedStatement?
- Como acontece com a classe Statement, depende do
tipo de cláusula SQL utilizada. Por exemplo, uma
cláusula do tipo UPDATE é feita da seguinte
maneira -
- PreparedStatement pstmt con.prepareStatement(
"UPDATE table4 SET m ? WHERE x ?") - pstmt.setLong(1, 123456789)
- pstmt.setLong(2, 100000000)
- pstmp.executeUpdate()
57Mapeamento de tipos
- O mesmo cuidado tomado quando se se utilizava
leitura de valores de campos com os métodos
get(campo) com relação aos mapeamento de tipos
também deve ser tomado quando se utiliza métodos
set(ordem do parâmetro, valor).
58Tabela de mapeamento de tipos
59Associação de valores NULL
- Para se associar NULL a um valor de parâmetro,
utiliza-se o método setNull disponibilizado pela
PreparedStament. - public void setNull(int parameterIndex,int
sqlType) - throws SQLException
- O segundo parâmetro é representados pelas
constantes da classe Types, do pacote java.sql.
60Exemplo
- ...
- PreparedStatement pstmt con.prepareStatement(
"UPDATE table4 SET m ? WHERE x ?") - pstmt.setLong(1, 123456789)
- // Segundo parâmetro NULL num campo tipo TIME
- pstmt.setNull(2,java.sql.Types.TIME)
- ...
-
-
61Associação de Large Objects (LOB)
- Para se associar large objects a parâmetros
utiliza-se métodos do tipo setStream - setBinaryStream para leitura de objetos binários
- setAsciiStream para leitura de caracteres ASCII
- setUnicodeStream para leitura de caracteres
Unicode
62Exemplo
- ...
- File file new java.io.File("/tmp/data")
- int fileLength file.length()
- InputStream fin new java.io.FileInputStream(file
) - PreparedStatement pstmt con.prepareStatement(
"UPDATE Table5 SET stuff ? WHERE index 4") - pstmt.setBinaryStream (1, fin, fileLength)
- pstmt.executeUpdate()
- ...
-
-
63Stored Procedures (I)
- Stored procedures são procedimentos armazenados
no servidor de BD para um determinado fim. - A execução de stored procedures geralmente é mais
rápida, pois o procedimento já está armazenado no
servidor e já de forma pré-compilada.
64Stored Procedures (II)
- É possível passar parâmetros e receber
parâmetros ou conjunto de dados de uma stored
procedure. - Os parãmetros de uma stored procedure são
classificados em três tipos - IN somente de entrada
- OUT somente de saída
- IN/OUT entrada/saída
65Classe CallableStatement
- Classe que possibilita a invocação de stored
procedures em JBDC. - Atráves de métodos da classe é possível passar a
consultar parâmetros. - Sua instanciação também é feita com base em uma
conexão e os mesmos cuidados com mapeamento de
tipos também devem ser tomados .
66Exemplo
- CallableStatement cstmt con.prepareCall( "call
reviseTotal(?)") - cstmt.setByte(1, 25)
- cstmt.registerOutParameter(1, java.sql.Types.TINYI
NT) - cstmt.executeUpdate()
- byte x cstmt.getByte(1)
67Transações (I)
- Através da instância Connection é possível
controlar transação via JDBC. - Quando Connection é criada, o esquema de controle
de transações é sempre auto-commit, ou seja,
terminada a execução de um statement, um sinal de
commit é enviado. Cada statement é comitado
individualmente e cada transação consiste de um
único statement.
68Transações (II)
- Quando o mecanismo de auto-commit é desabilitado
( método setAutoCommit(false)), a transação não
termina até que o método commit() ou rollback()
tenha sido invocado. - É possível, ainda, definir o nível de isolamento
das transações, através do método
setTransactionIsolation(nível). O nível de
isolamento é definido através de constantes da
classe Connection.