Nesta aula vamos aprender a fazer um programa em Java que faça uma conexão com um banco de dados.
O banco de dados que vamos utilizar é o MySQL.
Devemos obrigatoriamente seguir os passos:
Para acessar um banco de dados, primeiro precisamos ter acesso à um banco de dados.
O Xampp é um framework que possibilitará ter o MySql e um agente de acesso ao banco de dados.
Faça o download em https://www.apachefriends.org/index.html
Instale o xampp no seu computador, de preferência no diretório sugerido (C:\xampp)
Abra o programa e ligue o apache e o MySql.
Clique em admin
no MySql para abrir o agente administrador do banco de dados.
new
para criar um novo banco de dadosveterinario_unip
SQL
para entrar com um comando sql no banco de dados.Animais
CREATE TABLE Animais(
ID int NOT NULL AUTO_INCREMENT,
Nome varchar(255) NOT NULL,
Idade int,
PRIMARY KEY (ID)
);
Neste comando
Conectado a este Banco de Dados podemos
Inserir uma nova entrada:
INSERT INTO Animais(Nome, Idade) VALUES("Brutus", 12);
Listar todas as linhas:
SELECT * FROM Animais;
Fazer uma busca por todas as ocorrências que contenham a palavra "Br" como substring no nome, ignorando o case:
SELECT * FROM Animais WHERE LOWER(Nome) LIKE LOWER("%Br%");
O Driver é um arquivo .jar
distribuídos pela própria empresa do banco de dados.
Para encontrar o driver do mysql basta procurar por "jdbc mysql driver", e escolher a "distribuição independente da plataforma".
Depois de baixar o driver, você deve incluir o .jar em seu projeto como uma biblioteca externa.
No Eclipse, por exemplo, clique com o botão da direita no projeto > properties > java build path > Libraries > classpath > add external jar; escolha o arquivo baixado.
Para fazer a conexão usaremos a interface Connection
de java.sql.Connection
. Criaremos um objeto filho de Connection
através do método estático DriverManager
do java.sql.DriverManager
:
static private String USER = "root";
static private String PASS = "";
static private String DATABASE = "veterinario_unip";
static private String URL = "jdbc:mysql://localhost:3306/" + DATABASE;
static void testaConnection() {
try (Connection c = DriverManager.getConnection(URL, USER, PASS)){
System.out.println("Conexao estabelecida");
}catch(Exception e) {
e.printStackTrace();
}
}
onde
USER
é o usuárioPASS
é o password do banco de dadosDATABASE
é o banco de dados que será usadoURL
é o endereço do banco de dados, no caso o banco de dados está instalado em meu computador, então o endereço, por padrão, será "jdbc:mysql://localhost:3306/"
, concatenado com o nome do banco de dados.Para atualizar o banco de dados vamos usar o PreparedStatement
e adicionar um Animal
no banco de dados:
static public void addAnimal(Animal animal) {
final String query = "INSERT INTO Animais(Nome, Idade) VALUES(?, ?);";
try (Connection c = DriverManager.getConnection(URL, USER, PASS)){
PreparedStatement pstm = c.prepareStatement(query);
pstm.setString(1, animal.getNome());
pstm.setInt(2, animal.getIdade());
int result = pstm.executeUpdate();
System.out.println("Resultado de adicionar animal " + animal);
System.out.println("numero de linhas modificadas " + result);
}catch(Exception e) {
e.printStackTrace();
}
}
Os passos funcionam assim:
Animal
de entrada, lembrando que Gato
tem os campos id (int)
e nome (String)
.?
onde queremos inserir as palavras de entrada: "INSERT INTO Animais VALUES (?, ?)"
PreparedStatement
à partir da conexão. Este objeto recebe como parâmetro o comando para inserir uma entrada no banco de dados.?
que deixamos no comando, pedimos para o PreparedStatement
fazer isso: com pstm.setInt(1, animal.getId())
pedimos para colocar um int
no primeiro ?
e o valor deste inteiro será animal.getId()
; com pstm.setString(2, animal.getNome());
pedimos para inserir uma String
no segundo ?
e o valor desta String
será animal.getNome()
.PreparedStatement
executar a atualização programada com pstm.executeUpdate();
.Para fazer uma busca em um banco de dados precisamos usar o ResultSet
para acessar o resultado da busca. No exemplo à seguir vamos fazer recuperar todos os gatos na tabela.
static public List<Animal> getTodosAnimais() {
List<Animal> animais = new ArrayList<>();
final String query = "SELECT * FROM Animais;";
try (Connection c = DriverManager.getConnection(URL, USER, PASS)){
Statement stm = c.createStatement();
ResultSet rs = stm.executeQuery(query);
while(rs.next()) {
String nome = rs.getString("Nome");
int idade = rs.getInt("Idade");
Animal animal = new Animal(nome, idade);
animais.add(animal);
}
}catch(Exception e) {
e.printStackTrace();
}
return animais;
}
Os passos funcionam da seguinte forma:
"SELECT * FROM Animais;"
(desta vez não precisamos colocar o ?
)Statement
à partir da conexão. Este objeto fará a busca. Perceba que não precisamos criar um PreparedStatement
, pois não temos o caracter especial ?
.Statement
realizar a busca e criamos um ResultSet
para receber o resultado da busca.ResultSet
precisamos usar o método next()
, este método fará o ponteiro do ResultSet
ir para a próxima entrada do resultado, retornando true
enquanto tiver uma próxima entrada.ResultSet
podemos pegar o valor desta entrada pelo nome da coluna, especificando qual é o tipo de dado que irá retorna: rs.getInt("idade");
pede para pegar a coluna idade
como um inteiro; rs.getString("nome");
pede para pegar a coluna nome
como uma String
.Agora vamos fazer uma busca recebendo uma palavra, queremos encontrar todas as ocorrências que contenham a palavra como substring
static public List<Animal> buscaAnimais(String key) {
List<Animal> animais = new ArrayList<>();
final String query = "SELECT * FROM Animais WHERE LOWER(Nome) LIKE LOWER(?);";
try (Connection c = DriverManager.getConnection(URL, USER, PASS)){
PreparedStatement pstm = c.prepareStatement(query);
pstm.setString(1, "%" + key + "%");
ResultSet rs = pstm.executeQuery();
while(rs.next()) {
String nome = rs.getString("Nome");
int idade = rs.getInt("Idade");
Animal animal = new Animal(nome, idade);
animais.add(animal);
}
}catch(Exception e) {
e.printStackTrace();
}
return animais;
}
DAO
O padrão de arquitetura DAO
significa Data Access Object.
É o padrão que trabalha com a responsabilidade de transformar dados em objetos.
Assim como o MVC
, consiste em separar a interface da implementação.
Para usar o padrão DAO
em java devemos ter uma interface que defina a funcionalidade de sua responsabilidade: transformar dados persistentes em objetos java.
Esta interface independe se estes dados serão recuperados de um csv
, banco de dados, ou qualquer outra forma.
Se formos seguir o exemplo desta aula teremos como interface DAO
:
package dao;
import java.util.List;
import entidade.Animal;
public interface Dao {
public void addAnimal(Animal animal);
public List<Animal> getTodosAnimais();
public List<Animal> buscaAnimais(String key);
}
Uma implementação possível da interface é fazer uma classe que lê os dados em um arquivo csv
, uma outra pode ler de um banco de dados MySql
.
A seguir uma implementação que lê de um banco de dados MySql
:
package dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import entidade.Animal;
public class DaoMySql implements Dao{
static private final String USER = "root";
static private final String PASS = "";
static private final String DATABASE = "veterinario_unip";
static private final String URL = "jdbc:mysql://localhost:3306/" + DATABASE;
static void testaConnection() {
try (Connection c = DriverManager.getConnection(URL, USER, PASS)){
System.out.println("Conexao estabelecida");
}catch(Exception e) {
e.printStackTrace();
}
}
@Override
public void addAnimal(Animal animal) {
final String query = "INSERT INTO Animais(Nome, Idade) VALUES(?, ?);";
try (Connection c = DriverManager.getConnection(URL, USER, PASS)){
PreparedStatement pstm = c.prepareStatement(query);
pstm.setString(1, animal.getNome());
pstm.setInt(2, animal.getIdade());
int result = pstm.executeUpdate();
System.out.println("Resultado de adicionar animal " + animal);
System.out.println("numero de linhas modificadas " + result);
}catch(Exception e) {
e.printStackTrace();
}
}
@Override
public List<Animal> getTodosAnimais() {
List<Animal> animais = new ArrayList<>();
final String query = "SELECT * FROM Animais;";
try (Connection c = DriverManager.getConnection(URL, USER, PASS)){
Statement stm = c.createStatement();
ResultSet rs = stm.executeQuery(query);
while(rs.next()) {
String nome = rs.getString("Nome");
int idade = rs.getInt("Idade");
Animal animal = new Animal(nome, idade);
animais.add(animal);
}
}catch(Exception e) {
e.printStackTrace();
}
return animais;
}
@Override
public List<Animal> buscaAnimais(String key) {
List<Animal> animais = new ArrayList<>();
final String query = "SELECT * FROM Animais WHERE LOWER(Nome) LIKE LOWER(?);";
try (Connection c = DriverManager.getConnection(URL, USER, PASS)){
PreparedStatement pstm = c.prepareStatement(query);
pstm.setString(1, "%" + key + "%");
ResultSet rs = pstm.executeQuery();
while(rs.next()) {
String nome = rs.getString("Nome");
int idade = rs.getInt("Idade");
Animal animal = new Animal(nome, idade);
animais.add(animal);
}
}catch(Exception e) {
e.printStackTrace();
}
return animais;
}
}
Usando o padrão que separa a interface da implentação, todo o código deve trabalhar com a interface, ou seja, com uma variável do tipo Dao
, assim o código funcionará independente da implementação.
public static void main(String[] args) {
// aqui a implementação é escolhida
Dao dao = new DaoMySql();
// em todo os restante do código a interface Dao é usada
dao.addAnimal(new Animal("doguinho", 20));
dao.addAnimal(new Animal("caramelo", 21));
for(Animal a: dao.getTodosAnimais()) {
System.out.println(a);
}
for(Animal a: dao.buscaAnimais("c")) {
System.out.println(a);
}
}
Usando estes componentes podemos fazer qualquer comando simples em um banco de dados. Só lembre que:
PreparedStatement
Statement
executeQuery
e receber um ResultSet
executeUpdate
Raramente iremos precisar fazer uma atualização ou uma busca usando argumentos pré-programados.
Normalmente é o usuário final quem deve fornecer os argumentos para usar na nossa busca ou atualização.
Neste caso nunca devemos concatenar uma String de um comando com uma String fornecida pelo usuário.
Sob o risco do sistema sofrer um injection atack.
O recomendável para esta situação é usar a classe PreparedStatement