0

Trabalhando com Banco de Dados utilizando JDBC e JPA(Revisão)

Vinicius Almeida
Vinicius Almeida

Venho aqui trazer para vocês mais um resumo de conclusão de módulo. Caso queira rever os conceitos abordados durante o curso, você está no lugar certo!


Trabalhando com Banco de Dados utilizando JDBC e JPA

Introdução ao JDBC

CREATE database digital_innovation_one;
​
Use digital_innovation_one;
​
CREATE TABLE aluno (
 id INTEGER PRIMARY KEY AUTO_INCREMENT,
 nome VARCHAR(80) NOT NULL,
 idade INTEGER NOT NULL,
 estado CHARACTER(2) NOT NULL
);
​
INSERT INTO aluno(nome, idade, estado) VALUES ('Pedro', 20, 'RJ');
INSERT INTO aluno(nome, idade, estado) VALUES ('Maria', 35, 'AC');
INSERT INTO aluno(nome, idade, estado) VALUES ('Joao', 10, 'SC');
INSERT INTO aluno(nome, idade, estado) VALUES ('Ana', 51, 'GO');
  • Onde criamos o bando de dados digital_innovation_one, dizemos que estamos usando este banco. Criamos a tabela aluno e inserimos alguns valores nesta tabela.
  • Configurando Projeto Gradle
  • Para nosso projeto poder reconhecer nosso banco, precisamos adicionar a dependência dentro do projeto gradle no arquivo build.gradle. No campo dependencies, o professor adiciona a seguinte linha:
  • compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.17'
  • Mas recomendo pegar a dependência mais recente no site MVNreposytory e escolher o tipo de projeto que no nosso caso é um projeto Gradle.
  • Após declarar a dependência, o InteliJ irá baixa-lá automaticamente. Caso isso não aconteça, o intelij irá perguntar se você quer baixar a dependência.


  • O que é a JDBC?
  • JDBC(Java Database Connectivity) é uma API com diversas classes e interfaces escritas na linguagem Java que estão presentes nos pacotes java.sql e javax.sql. Elas permitem que programas em Java realizem conexões em bancos de dados para realizar consultas. Uma dessas classes principais é o driver JDBC que intermedia essa interação.
  • Sem a API JDBC, seria necessário conhecer o protocolo proprietário de cada banco de dados para se conectar e realizar consultas. Já com a API JDBC, é utilizada somente UMA interface Java para qualquer banco de dados, deixando o driver implementar as especificações de cada banco de dados, enquanto o desenvolvedor se preocupa apenas em selecionar um driver e criar as queries (neste caso, consultas SQL).
  • Se conectando a um SGBD
  • Utilizando as API's java.sql.Connection e java.sql.DriverManager, precisamos definir o driver(o SGBD que está utilizando), o endereço do seu SGBD(dataBaseAddress), o banco de dados que está utilizando(dataBaseName), o usuário e a senha.
  • Exemplo:
String driver = "mysql";
String dataBaseAddress = "localhost";
String dataBaseName = "digital_innovation_one";
String user = "root";
String password = "password";
  • Para deixar o código mais fácil e organizado, utilizamos um StringBuilder para criar a Url de conexão:
StringBuilder sb = new StringBuilder("jdbc:")
.append(driver).append("://")
.append(dataBaseAddress).append("/")
.append(dataBaseName);
​
String connectionUrl = sb.toString();
//Resultará na String:
//sb.toString() == "jdbc:mysql://localhost/digital_innovation_one"
  • Após isso fazemos a conexão com o banco pelo bloco Try/Catch:
try (Connection conn = DriverManager.getConnection(connectionUrl, user, password)) {
System.out.println("SUCESSO ao se conectar ao banco MySQL!");
} catch (SQLException e) {
System.out.println("FALHA ao se conectar ao banco MySQL!");
e.printStackTrace();
}
  • Se tudo estiver dado certo, você receberá uma mensagem de sucesso.
  • Classe DriverManager
  • Responsável pela comunicação com os drivers disponíveis. É utilizada para criar uma Connection com o banco de dados através de uma URL (que especifica driver, localização do BD e nome do BD).
  • Interface Connection
  • Representa a conexão com o banco de dados. Permite criar “Statements” que constroem consultas SQL.
  • O código de conexão mudou um pouco após criarmos um arquivo .properties para guardar os dados da conexão, onde criamos uma classe específica para a função, ficando assim:
public class ConnectionFactory {
​
 //Construtor declarado como privado. Evitando assim criar instâncias da fábrica.
 private ConnectionFactory() {
   throw new UnsupportedOperationException();
 }
​
 public static Connection getConnection() {
​
   // OBS: NÃO ESQUECER DE BAIXAR O DRIVER PARA O BANCO DE DADOS QUE IRÁ UTILIZAR! (Como demonstrado na parte 1 do curso)
​
   // 1 - Declarar objeto conexão (irá receber uma conexão após executar os passos abaixo)
   Connection connection = null;
​
   // 2 - Carregar arquivo de propriedades para pegar parâmetros necessários para se comunicar com o banco de dados
   try (InputStream input = ConnectionFactory.class.getClassLoader().getResourceAsStream("connection.properties")) {
​
     // 3 - Definir parâmetros para se conectar ao banco de dados MySQL.
     Properties prop = new Properties();
     prop.load(input);
​
     String driver = prop.getProperty("jdbc.driver");
     String dataBaseAddress = prop.getProperty("db.address");
     String dataBaseName = prop.getProperty("db.name");
     String user = prop.getProperty("db.user.login");
     String password = prop.getProperty("db.user.password");
​
     // 4 - Construção da string de conexão.
     StringBuilder sb = new StringBuilder("jdbc:")
         .append(driver).append("://")
         .append(dataBaseAddress).append("/")
         .append(dataBaseName);
​
     String connectionUrl = sb.toString(); //sb.toString() == "jdbc:mysql://localhost/digital_innovation_one"
​
     // 5 - Criar conexão usando o DriverManager, passando como parâmetros a string de conexão, usuário e senha do usuário.
     try {
       connection = DriverManager.getConnection(connectionUrl, user, password);
     } catch (SQLException e) {
       System.out.println("FALHA ao tentar criar conexão");
       throw new RuntimeException(e);
     }
​
   } catch (IOException e) {
     System.out.println("FALHA ao tentar carregar aquivos de propriedades");
     e.printStackTrace();
   }
​
   return connection;
 }
}
  • Consultas com JDBC
  • Statement – Executar SQL comuns
  • PreparedStatement – Executar SQL parametrizáveis
  • CallableStatement – Executar stored procedures
  • Obs : Preferir PreparedStatement ao Statement quando for parametrizar a consulta pois : Previne SQL Injection, melhora legibilidade e melhora desempenho.


  • Pegando dados de um SGBD
  • Existem 3 métodos para executar comandos SQL, sendo eles:
  • execute – Pode executar qualquer tipo de SQL.
  • executeQuery – Usado para executar “SELECT”.
  • executeUpdate – Usado para commandos de alteração de banco de dados (INSERT, UPDATE, DELETE, CREATE, ALTER).
  • Quando uma consulta SQL é executada trazendo um retorno, o seu retorno é um ResultSet.
  • ResultSet
  • Para extrair os dados de um ResultSet e armazenarmos em nossas variáveis ou objetos, precisamos transformar esses dados e fazemos isso através de getters como: getInt, getFloat e getString.
  • Para navegarmos em um ResultSet, necessitamos iterar as informações nele contidas e podemos fazer isso através do método next(), qual chama o próximo item de um ResultSet. Seu ponteiro sempre começa antes do primeiro item de um ResultSet e retorna um booleano True para cada chamada caso exista o próximo item.
  • Select
  • No exemplo dado em aula abaixo, estamos pegando os itens do banco de dados da tabela alunos e retornando uma lista de alunos:
​
   //Preparar lista que irá retornar alunos após consultar o banco de dados;
   List<Aluno> alunos = new ArrayList<>();
​
   try (Connection conn = ConnectionFactory.getConnection()) {
     //Preparar consulta SQL.
     String sql = "SELECT * FROM aluno";
​
     //Preparar statement com os parâmetros recebidos (nesta função não tem parâmetros, pois irá retornar todos os valores da tabela aluno)
     PreparedStatement stmt = conn.prepareStatement(sql);
​
     //Executa consulta e armazena o retorno da consulta no objeto "rs".
     ResultSet rs = stmt.executeQuery();
​
     //Criar um objeto aluno e guardar na lista de alunos.
//Para cada método getter temos como parâmetro o nome da coluna.
     while(rs.next()){
       int id = rs.getInt("id");
       String nome = rs.getString("nome");
       int idade = rs.getInt("idade");
       String estado = rs.getString("estado");
​
       alunos.add(new Aluno(
           id,
           nome,
           idade,
           estado
       ));
     }
   } catch (SQLException e) {
     System.out.println("Listagem de alunos FALHOU!");
     e.printStackTrace();
   }
​
   //Retornar todos os alunos encontrados no banco de dados.
   return alunos;
 }
  • Select com Parâmetro
  • Muito semelhante ao exemplo anterior, aqui realizamos uma consulta com um determinado filtro:
public Aluno getById(int id) {
//Preparar objeto aluno para receber os valores do banco de //dados.
   Aluno aluno = new Aluno();
​
   try (Connection conn = ConnectionFactory.getConnection()) {
     //Preparar consulta SQL
//Onde o ponto de interrogação representa a váriável id //passada no parâmetro do método.
     String sql = "SELECT * FROM aluno WHERE id = ?";
      
      
     //Preparar statement com os parâmetros recebidos
PreparedStatement stmt = conn.prepareStatement(sql);
//Aqui dizemos que o primeiro '?' será representado pela //varíavel id que será recebida no parâmetro do método
     stmt.setInt(1, id);
​
     //Executa consulta e armazena o retorno da consulta no objeto "rs".
     ResultSet rs = stmt.executeQuery();
​
//Guardar valores retornados da tabela aluno no objeto aluno
     if (rs.next()){
       aluno.setId(rs.getInt("id"));
       aluno.setNome(rs.getString("nome"));
       aluno.setIdade(rs.getInt("idade"));
       aluno.setEstado(rs.getString("estado"));
     }
​
   } catch (SQLException e) {
     System.out.println("Listagem de alunos FALHOU!");
     e.printStackTrace();
   }
​
   //Retorna aluno encontrado no banco de dados.
   return aluno;
 }
  • Insert
  • Seguimos basicamente a mesma linha dos exemplos de cima para inserção de dados em um SGBD:
public void create(Aluno aluno) {
   try (Connection conn = ConnectionFactory.getConnection()) {
​
//Preparar SQL para inserção de dados do aluno.
     String sql = "INSERT INTO aluno(nome, idade, estado) VALUES(?, ?, ?)";
​
     //Preparar statement com os parâmetros recebidos
     PreparedStatement stmt = conn.prepareStatement(sql);
     stmt.setString(1 , aluno.getNome());
     stmt.setInt(2, aluno.getIdade());
     stmt.setString(3 , aluno.getEstado());
​
//Executa inserção e armazena o numero de linhas afetadas
     int rowsAffected = stmt.executeUpdate();
​
     System.out.println("Inserção BEM SUCEDIDA!. Foi adicionada " + rowsAffected + " linha");
   } catch (SQLException e) {
     System.out.println("Inserção FALHOU!");
     e.printStackTrace();
   }
 }
  • Delete
 public void delete(int id) {
   try (Connection conn = ConnectionFactory.getConnection()) {
​
     //Preparar SQL para deletar uma linha.
     String sql = "DELETE FROM aluno WHERE id = ?";
​
     //Preparar statement com os parâmetros recebidos
     PreparedStatement stmt = conn.prepareStatement(sql);
     stmt.setInt(1 , id);
​
     //Executa delete e armazena o numero de linhas afetadas
     int rowsAffected = stmt.executeUpdate();
​
     System.out.println("Delete BEM SUCEDIDA! Foi deletada " + rowsAffected + " linha");
   } catch (SQLException e) {
     System.out.println("Delete FALHOU!");
     e.printStackTrace();
   }
 }
  • Update
 public void update(Aluno aluno) {
   try (Connection conn = ConnectionFactory.getConnection()) {
​
     //Preparar SQL para atualizar linhas.
     String sql = "UPDATE aluno SET nome = ?, idade = ?, estado = ? WHERE id = ?";
​
     //Preparar statement com os parâmetros recebidos
     PreparedStatement stmt = conn.prepareStatement(sql);
     stmt.setString(1, aluno.getNome());
     stmt.setInt(2, aluno.getIdade());
     stmt.setString(3, aluno.getEstado());
     stmt.setInt(4, aluno.getId());
​
//Executa atualização e armazena o numero de linhas afetadas
     int rowsAffected = stmt.executeUpdate();
​
     System.out.println("Atualização BEM SUCEDIDA! Foi atualizada: " + rowsAffected + " linha");
   } catch (SQLException e) {
     System.out.println("Atualização FALHOU!");
     e.printStackTrace();
   }
 }

Introdução ao JPA

  • Slides da Aula :
  • https://github.com/danielkv7/digital-innovation-one/tree/master/Aula_JPA_basico
  • Projeto da Aula :
  • https://github.com/danielkv7/jpa-basico
  • Um problema de produtividade começou a ser notado no desenvolvimento de aplicações Web Java. Os desenvolvedores perceberam que a maior parte do tempo era gasto com queries SQL através do JDBC.
  • Um outro problema percebido era a mudança de paradigma. A programação orientada a objetos (ex: Java) é diferente do esquema entidade relacional (ex: SGBDs tradiconais), sendo necessário esquematizar dois modelos para um mesmo sistema.Para padronizar as interfaces das implementações ORM (Mapeamento Objeto Relacional) foi criada uma ESPECIFICAÇÃO oficial chamada JPA (ou Java Persistence API). Ela descreve como deve ser o comportamento dos frameworks Java ORM que desejarem IMPLEMENTAR a sua especificação.
  • Logo SOMENTE com a ESPECIFICAÇÃO JPA NÃO será possível executar operações entre a aplicação e o banco de dados.
  • Apesar de ser SOMENTE a especificação, o JPA possui algumas classes, interfaces e anotações que ajudam o desenvolvedor a abstrair o código.
  • Esses artefatos estão presentes no pacote javax.persistence que ajudam a manter o código independente da implementação utilizada. Lembrando que para persistir dados com JPA, é preciso escolher uma implementação que irá executar todo o trabalho (serão utilizados Hibernate e EclipseLink).
  • Baixando as Dependências
  • Para que não ocorra nenhum erro na execução, eu aconselho que sejam baixadas as versões estáveis mais recentes das tecnologias utilizadas aqui.
  • Download Hibernate.
  • Download EclipseLink.
  • Download JDBC.
  • javax.persistence.
  • Para implementar uma dependência, vamos até o arquivo build Gradle e colocamos a linha que pegamos dos links acima dentro de dependencies.
  • Exemplo:
// Drive JDBC que sera utilizado pelos frameworks que implementam o JPA
 // https://mvnrepository.com/artifact/mysql/mysql-connector-java
 compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.26'
​
​
// Implementacao Hibernate
 // https://mvnrepository.com/artifact/org.hibernate/hibernate-core
 compile group: 'org.hibernate', name: 'hibernate-core', version: '5.5.6.Final'
  • Configurando o arquivo persistence.xml
  • Para começar, iremos implementar o ORM Hibernate e para isso precisamos criar e configurar o arquivo .xml com as configurações de persistência.
  • Para isso, criamos um package chamado resources, assim como nas aulas anteriores. Dentro do package Resources criamos outro package chamado META-INF e dentro deste package, damos o clique direito -> New -> File e então damos o nome de persistence.xml
  • Após isso colocamos o seguinte código:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
      version="2.2">
​
 <!-- Unidade de persistencia da parte 2 do curso (Com implementacao Hibernate ou EclipseLink) -->
 <persistence-unit name="part2-DIO">
​
   <description> Unidade de persistencia da parte 2 do tutorial basico de JPA da Digital Innovation One com implementacoes (Hibernate ou EclipseLink) </description>
​
<!-- Implementacao do JPA -->
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
​
   <!-- Classes (entidades) que serao mapeadas -->
   <class>classes.Aluno</class>
   <class>classes.Estado</class>
​
   <!-- Configuracoes de conexao ao banco de dados e do Hibernate/EclipseLink (Trocar os campos de usuário e senha conforme foi configurado seu SGBD)-->
   <properties>
     <!-- Configuracoes do banco de dados -->
     <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost/digital_innovation_one" />
     <property name="javax.persistence.jdbc.user" value="root" />
     <property name="javax.persistence.jdbc.password" value="password" />
     <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver" />
​
     <!-- Configuracoes do Hibernate (os parametros so sao reconhecidos se estiver usando a implementacao do Hibernate)-->
     <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL8Dialect" />
     <!-- Mostra ou esconde o sql da consulta -->
     <property name="hibernate.show_sql" value="true" />
     <!-- Formata ou não o sql -->
     <property name="hibernate.format_sql" value="true" />
     <!-- Sempre que for rodado o programa, o banco é recriado -->
     <property name="hibernate.hbm2ddl.auto" value="create" /> <!-- Possible values for hibernate.hbm2ddl.auto are: validate, update, create, create-drop -->
​
   </properties>
 </persistence-unit>
</persistence>
  • Criando as Entidades
  • Para esta aula, faremos uso de duas entidades, Aluno e estado.
  • Entidade Aluno:
package classes;
​
import javax.persistence.*;
​
@Entity
public class Aluno {
​
 @Id
 @GeneratedValue(strategy= GenerationType.IDENTITY)
 private int id;
​
 @Column(nullable = false)
 private String nome;
​
 @Column(nullable = false)
 private int idade;
​
 @ManyToOne(fetch = FetchType.LAZY)
 private Estado estado;
​
 public Aluno() { }
​
 public Aluno(String nome, int idade) {
   this.nome = nome;
   this.idade = idade;
 }
​
 public Aluno(String nome, int idade, Estado estado) {
   this.nome = nome;
   this.idade = idade;
   this.estado = estado;
 }
​
 public int getId() {
   return id;
 }
​
 public void setId(int id) {
   this.id = id;
 }
​
 public String getNome() {
   return nome;
 }
​
 public void setNome(String nome) {
   this.nome = nome;
 }
​
 public int getIdade() {
   return idade;
 }
​
 public void setIdade(int idade) {
   this.idade = idade;
 }
​
 public Estado getEstado() {
   return estado;
 }
​
 public void setEstado(Estado estado) {
   this.estado = estado;
 }
​
 @Override
 public String toString() {
   return "Aluno{" +
       "id=" + id +
       ", nome='" + nome + '\'' +
       ", idade=" + idade +
       ", estado=" + estado +
       '}';
 }
}
  • Entidade Estado:
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
​
@Entity
public class Estado {
​
 @Id
 @GeneratedValue(strategy= GenerationType.IDENTITY)
 private int id;
​
 @Column(nullable = false)
 private String nome;
​
 @Column(nullable = false)
 private String sigla;
​
 @OneToMany(
     mappedBy = "estado",
     cascade = CascadeType.ALL,
     orphanRemoval = true
 )
 private List<Aluno> alunos = new ArrayList<>();
​
 public Estado() { }
​
 public Estado(String nome, String sigla) {
   this.nome = nome;
   this.sigla = sigla;
 }
​
 public Estado(String nome, String sigla, List<Aluno> alunos) {
   this.nome = nome;
   this.sigla = sigla;
   this.alunos = alunos;
 }
​
 public int getId() {
   return id;
 }
​
 public void setId(int id) {
   this.id = id;
 }
​
 public String getNome() {
   return nome;
 }
​
 public void setNome(String nome) {
   this.nome = nome;
 }
​
 public String getSigla() {
   return sigla;
 }
​
 public void setSigla(String sigla) {
   this.sigla = sigla;
 }
​
 public List<Aluno> getAlunos() {
   return alunos;
 }
​
 public void setAlunos(List<Aluno> alunos) {
   this.alunos = alunos;
 }
​
 @Override
 public String toString() {
   return "Estado{" +
       "id=" + id +
       ", nome='" + nome + '\'' +
       ", sigla='" + sigla + '\'' +
       ", alunos=" + alunos +
       '}';
 }
}
  • Notations
  • Se você reparar nas classes, verá que estamos utilizando algumas Notations(Identificadas pelo @). Estas notations são necessárias para dizer ao Hibernate ou EclipseLink como lidar com a nossa Classe.
  • @Entity
  • Se faz obrigatório o uso desta notation para o JPA entender que esta classe é uma entidade.
  • @Id
  • Notation obrigatória para informar ao JPA a chave primária de sua tabela.
  • @GeneratedValue(strategy= GenerationType.IDENTITY)
  • Aqui estamos passando a obrigação de criar a chave primária para o SGBD com a estratégia de geração do tipo IDENTITY.
  • @Column(nullable = false)
  • Nesta notation definimos que a coluna não pode possuir valores nulos.
  • @ManyToOne(fetch = FetchType.LAZY)
  • Aqui estamos definindo o relacionamento entre Tabelas e Entidades, onde estamos dizendo que possui o relacionamento muitos para um(Nx1) e que esta Entidade deverá ser carregada no modo LAZY(Significa que a entidade referenciada só será carregada se for explicitamente requisitada).
  • @OneToMany
  • Define um relacionamento de um para muitos. Nas aulas aprendemos a configurar três campos, sendo eles:
  • mappedBy : Uso obrigatório o qual representa o campo que é dono do relacionamento(A parte N do relacionamento).
  • cascade : Define as configurações para operações em cascata.
  • Executando as implementações do Hibernate
  • Criando um Gerenciador de Entidades
  • O primeiro passo desta etapa é criar um gerenciador de entidades, especificando de onde devem vir as configurações:
// 1 - Passos iniciais para criar um gerenciador de entidades com o banco //de dados especificado no arquivo "persistence.xml"
​
//Informamos que dentro de nosso persistence.xml, o gerenciador deve usar //as configurações da persistence-unit "part2-DIO"
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("part2-DIO");
​
//Criamos o Gerenciador de Entidades
EntityManager entityManager = entityManagerFactory.createEntityManager();
  • *Lembrando que se as configurações para Hibernate ou EclipseLink não estiverem presentes dentro da persistence-unit "part2-DIO", o programa apresentará erro em tempo de execução.
  • Inserindo Dados no SGBG
  • O JPA trabalha com transações, então para poder realizar comandos SQL que alterem dados, precisamos definir o início da transação, fazer as operações requisitadas e então dar um commit em nossa transação como no exemplo abaixo onde estamos iniciando a Transação através do comando entityManager.getTransaction().begin(), adicionamos os valores dos objetos ao banco através do comando entityManager.persist(objeto) e então finalizamos a transação através do comando entityManager.getTransaction().commit().
  • *Importante lembrar que sempre que terminamos de utilizar o gerenciador, devemos fechar o entityManager e o entityManagerFactory. Ambos podem ser finalizamos com o método close().
// 2.1 - Criar instancias para serem adicionadas no banco de dados
​
Estado estadoParaAdicionar = new Estado("Rio de Janeiro", "RJ");
Aluno alunoParaAdicionar = new Aluno("Daniel", 29, estadoParaAdicionar);
​
// 2.2 - Inicia uma trasacao para adiconar as instancias no banco de //dados
   entityManager.getTransaction().begin();
​
   entityManager.persist(estadoParaAdicionar);
   entityManager.persist(alunoParaAdicionar);
​
   entityManager.getTransaction().commit();
    
entityManager.close();
entityManagerFactory.close();
  • Procurando Dados pelo Gerenciador
  • Podemos resgatar dados de tabelas do SGBD através do método find(), onde passamos como parâmetro a Entidade que desejamos procurar e sua chave primária.
  • No exemplo abaixo, estamos procurando o Estado que tenha seu id = 1 e armazenando seu resultado na variável estadoEncontrado, e um aluno que também tenha seu id = 1 e armazenando seu resultado na variável alunoEncontrado.
//3 - Resgatar instâncias no banco de dados
Estado estadoEncontrado = entityManager.find(Estado.class, 1);
Aluno alunoEncontrado = entityManager.find(Aluno.class, 1);
​
entityManager.close();
entityManagerFactory.close();
  • Fazendo UPDATE pelo Gerenciador
  • Como estamos fazendo uma alteração no banco de dados, precisamos definir o corpo de uma Transaction. Agora utilizaremos os resultados armazenados pela consulta do código acima.Iniciamos a transação, alteramos seus valores através de seus Setters e finalizamos a trasação. O gerenciador automaticamente reconhece que já existe um objeto com o Id armazenado em alunoEncontrado e apenas salva as alterações realizadas no SGBD.
entityManager.getTransaction().begin();
​
alunoEncontrado.setNome("Karam");
alunoEncontrado.setIdade(20);
​
entityManager.getTransaction().commit();
​
entityManager.close();
entityManagerFactory.close();
  • Fazendo Deleções pelo Gerenciador
  • Novamente, como estamos alterando os dados dentro do SGBD, precisamos trabalhar com transactions. Removemos uma instância da entidade através do comando entityManager.remove(objeto), onde passamos a instância da entidade que desejamos remover.
// 5 - Remover uma entidade
entityManager.getTransaction().begin();
​
entityManager.remove(alunoEncontrado);
​
entityManager.getTransaction().commit();
​
entityManager.close();
entityManagerFactory.close();
  • Utilizando o EclipseLink
  • Para utilizar o EclipseLink, basta mudarmos nossa implementação no arquivo persistence.xml. Para isso, basta trocarmos nossa implementação de Hibernate para EclipseLink, deixando nosso código assim:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
      version="2.2">
​
 <!-- Unidade de persistencia da parte 2 do curso (Com implementacao Hibernate ou EclipseLink) -->
 <persistence-unit name="part2-DIO">
​
   <description> Unidade de persistencia da parte 2 do tutorial basico de JPA da Digital Innovation One com implementacoes (Hibernate ou EclipseLink) </description>
​
<!-- Implementacao do JPA -->
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
​
   <!-- Classes (entidades) que serao mapeadas -->
   <class>classes.Aluno</class>
   <class>classes.Estado</class>
​
   <!-- Configuracoes de conexao ao banco de dados e do Hibernate/EclipseLink (Trocar os campos de usuário e senha conforme foi configurado seu SGBD)-->
   <properties>
     <!-- Configuracoes do banco de dados -->
     <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost/digital_innovation_one" />
     <property name="javax.persistence.jdbc.user" value="root" />
     <property name="javax.persistence.jdbc.password" value="password" />
     <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver" />
​
     <!-- Configuracoes do EclipseLink (os parametros so sao reconhecidos se estiver usando a implementacao do EclipseLink)-->
<property name="eclipselink.target-database" value="MySQL"/>
<property name="eclipselink.logging.level.sql" value="FINE" />
<property name="eclipselink.logging.parameters" value="true" />
<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
​
   </properties>
 </persistence-unit>
</persistence>
​
  • É necessário que também seja adicionado ao arquivo build.gradle a dependência do Eclipse. Como estamos utilizando a Interface do JPA a qual implementa uma das tecnologias de persistência(Hibernate ou EclipseLink), não precisamos mudar nada no código da execução.
  • Linguagens de consulta orientada a objetos
  • Nas aulas tratamos especificamente de JPQL mas é importante sabe que também existem a HQL(Hibernate Query Language) e a EQL(EclipseLink Query Language).
  • O JPQL (Java Persistence Query Language) é uma linguagem de consulta independente orientada a objetos definida pelo JPA.
  • JPQL é usado para realizar consultas no banco de dados. É inspirado no SQL (inclusive a sua sintaxe), porém ele interage com o banco de dados através das entidades do JPA, ao invés de interagir diretamente nas tabelas de banco de dados (como é no SQL).
  • Com o JPQL é possíveis utilizar as propriedades de orientação a objetos nas consultas realizadas no banco de dados, através das entidades mapeadas, tal como herança.
  • Iniciando
  • Para usar o JPQL ou o JPA Criteria API é necessário ter um objeto da classe EntityManager, pois é através dos seus métodos createQuery (JPQL) e getCriteriaBuilder (JPA Criteria API) que se inicia a criação das consultas:
// 1 - Dados instanciados para serem utilizados como exemplo
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("part2-DIO");
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
Estado estadoParaAdicionar = new Estado("Rio de Janeiro", "RJ");
entityManager.persist(estadoParaAdicionar);
entityManager.persist(new Estado("Sao Paulo", "SP"));
entityManager.persist(new Aluno("Daniel", 29, estadoParaAdicionar));
entityManager.persist(new Aluno("Joao", 20, estadoParaAdicionar));
entityManager.persist(new Aluno("Pedro", 30, estadoParaAdicionar));
entityManager.getTransaction().commit();
​
  • Na primeira amostra o Professor utilizou o SQL nativo para fazer consultas no SGBD:
//2.3 - SQL nativo
​
//Trazendo somente 1 resultado
String sql = "SELECT * FROM Aluno WHERE nome = :nome ";
Aluno alunoSQL = (Aluno) entityManager
.createNativeQuery(sql, Aluno.class)
.setParameter("nome", nome)
.getSingleResult();
​
// Trazendo uma lista como resultado
String sqlList = "SELECT * FROM Aluno";
List<Aluno> alunoSQLList = entityManager
.createNativeQuery(sqlList, Aluno.class)
.getResultList();
  • Um dos problemas com esse tipo de abordagem é que caso as tabelas no banco mudem, precisamos alterar nossos métodos no programa. Outro problema é que para trazer apenas uma linha de dados, se faz necessário o uso de casting, o que pode causar um erro em tempo de execução.
  • Utilizando JPQL
  • Uma das vantagens de se utilizar este método é que podemos fazer operações em massa, ao invés de realizar operações em apenas uma instância por vez através de chaves primárias (como nos métodos do entityManager). Podemos também fazer funções de agregação e realizar consultas mais complexas.
  • Com o JPQL podemos dar um alias(Apelido) para a coluna que estamos filtrando os dados
 // Trazendo somente 1 resultado
   String jpql = "select a from Aluno a where a.nome = :nome";
   Aluno alunoJPQL = entityManager
       .createQuery(jpql, Aluno.class)
       .setParameter("nome", nome)
       .getSingleResult();
​
   // Trazendo uma lista como resultado
   String jpqlList = "select a from Aluno a where a.estado = :estado";
   List<Aluno> alunoJPQLList = entityManager
       .createQuery(jpqlList, Aluno.class)
       .setParameter("estado", estadoParaAdicionar)
       .getResultList();
​
   // Resultados das consultas acima
   System.out.println("Consulta alunoJPQL: " + alunoJPQL);
   alunoJPQLList.forEach(Aluno -> System.out.println("Consulta alunoJPQLList: " + Aluno));
  • Utilizando JPQL + JPA Metamodel
  • Para criar os JPA Metamodel de cada entidade será necessário adicionar o JAR “hibernate-jpamodelgen” através do Gradle, Maven ou manualmente. Esse JAR automatiza a criação de Metamodels (também existem outras organizações que oferecem esse tipo de solução).
  • É possível criar manualmente os JPA Metamodels de cada entidade que irão auxiliar na validação das consultas realizadas através do JPA Criteria API, porém isso seria trabalhoso demais. Por essa razão é mais fácil utilizar um gerador de Metamodels para automatizar esse processo.
  • Para o Hibernate devemos adicionar a dependência do JPA MetaModel que pode ser encontrado em :
  • https://mvnrepository.com/artifact/org.hibernate/hibernate-jpamodelgen
2.5 - JPA Criteria API + JPA Metamodel
​
// Trazendo somente 1 resultado
CriteriaQuery<Aluno> criteriaQuery = entityManager.getCriteriaBuilder().createQuery(Aluno.class);
Root<Aluno> alunoRoot = criteriaQuery.from(Aluno.class);
CriteriaBuilder.In<String> inClause = entityManager.getCriteriaBuilder().in(alunoRoot.get(Aluno_.nome));
inClause.value(nome);
criteriaQuery.select(alunoRoot).where(inClause);
Aluno alunoAPICriteria = entityManager.createQuery(criteriaQuery).getSingleResult();
​
// Trazendo uma lista como resultado
CriteriaQuery<Aluno> criteriaQueryList = entityManager.getCriteriaBuilder().createQuery(Aluno.class);
Root<Aluno> alunoRootList = criteriaQueryList.from(Aluno.class);
List<Aluno> alunoAPICriteriaList = entityManager.createQuery(criteriaQueryList).getResultList();
  • Uma das vantagens de se utilizar este método é que diferente dos anteriores, aqui temos suporte da IDE para escrever o código.
0
0

Comentários (0)

https://www.linkedin.com/in/vinicius-ornelas-587075128/

Brasil