Simplificando o Hibernate utilizando Panache - criando uma aplicação simples utilizando Quarkus Java + REST + CDI + Panache
Tags: quarkus, panache, jpa, hibernate
Published: 2021-02-07 03:03:05

### Tutorial: Quarkus — Simplificando o Hibernate utilizando Panache — criando uma aplicação simples utilizando Quarkus Java + REST + CDI + Panache

![Logo — Tartarugas e um Jacaré](https://cdn-images-1.medium.com/max/800/1*6kNyK7zvhXQPvatTwp1zeg.jpeg)


> [**_Se inscreva no meu canal do Youtube, vários conteúdos para Desenvolvedores: https://www.youtube.com/channel/UCzoyY_hIVs53dQUeY4yVkhA_**](https://www.youtube.com/channel/UCzoyY_hIVs53dQUeY4yVkhA)

>   

![](https://cdn-images-1.medium.com/max/800/0*rcTbDADz-U9nBVF4)

![](https://cdn-images-1.medium.com/max/800/0*tqd_Zn8CsZVe00kM.png)


#Introdução 
Este artigo tem o objetivo de apresentar uma alternativa para simplificar a implementação da camada de persistência em uma aplicação Java. A maioria dos desenvolvedores Java conhecem a especificação [JPA (Java Persistence API)](https://www.oracle.com/technetwork/java/javaee/tech/persistence-jsp-140049.html), que é uma interface comum para frameworks que trabalham com persistência de dados. Uma das implementações mais conhecidas é o Hibernate.

O Hibernate é um framework [ORM (Mapeamento Objeto Relacional)](https://stackoverflow.com/questions/1279613/what-is-an-orm-how-does-it-work-and-how-should-i-use-one), que tem como objetivo, facilitar o mapeamento das tabelas, atributos e relacionamentos de um banco de dados para uma classe java.

No exemplo abaixo, podemos ver uma das formas para implementação de uma consulta para obter todos os carros de uma base de dados. No primeiro trecho de código, observamos a criação do [EntityManagerFactory](https://docs.oracle.com/javaee/7/api/javax/persistence/EntityManagerFactory.html) e em seguida a criação de um [EntityManager](https://docs.oracle.com/javaee/7/api/javax/persistence/EntityManager.html), por fim, a consulta é criada retornando a lista de carros.

![Implementação para retornar a lista de carros](https://cdn-images-1.medium.com/max/800/0*16Z_Y5rKmTKdaDNL)

Como forma de comparação, veja no exemplo abaixo, a mesma implementação da recuperação da lista de todos os carros, utilizando o Panache.

![](https://cdn-images-1.medium.com/max/800/0*UvCKOorcK8ziaAZ2)

> O objetivo do Panache é simplificar a camada de persistência, principalmente das operações triviais.

No exemplo abaixo, podemos ver uma implementação para salvar um objeto carro no Banco de Dados. Explicando o código: O objeto carro é criado e “populado”, em seguida, ocorre a criação do EntityManagerFactory e do EntityManager. Antes de salvar o objeto é necessário abrir a conexão, salvar o carro e em seguida realizar o commit. Antes de terminar a execução do método é necessário fechar a conexão do banco de dados, através da instrução close();

![](https://cdn-images-1.medium.com/max/800/0*q6drdZ_KlN3-6bzf)

_* Exemplo adaptado da apostila da Caelum:_ [_https://www.caelum.com.br/apostila-java-web/uma-introducao-pratica-ao-jpa-com-hibernate/#trabalhando-com-os-objetos-o-entitymanager_](https://www.caelum.com.br/apostila-java-web/uma-introducao-pratica-ao-jpa-com-hibernate/#trabalhando-com-os-objetos-o-entitymanager)

No código-fonte abaixo, segue a implementação do salvar, utilizando o Panache.

> Para utilizar os benefícios do Panache é necessário que a entidade estenda a classe PanacheBaseEntity. Dessa forma, a Classe que herda terá diversos métodos prontos para serem utilizados.

Voltando para o código, na primeira parte do código o Carro é instanciado e “populado”, em seguida, invoca o método estático (persist) da Classe Carro para salvar o objeto no banco de dados, para finalizar devolve o objeto para a requisição _REST_.

![](https://cdn-images-1.medium.com/max/800/0*Gsbz-BfsTywa6_aW)

> O Panache é responsável por gerenciar toda a transação, desde da abertura, commit e o fechamento da transação.

> A ideia é facilitar a implementação, melhorando assim a produtividade, já que o código fica bem mais simples, se comparado a forma tradicional.

### Métodos da classe **PanacheEntityBase**

Ao estender a classe PanacheEntityBase, a classe herda vários métodos úteis, como: _Listar todos, salvar, atualizar, remover, buscar um objeto, retornar a quantidade de objetos de uma determinada tabela_.

> Listando carros com o nome Fusca, basta escrever: Car.find(“name”, “fusca”);

> Listando carros ordenados por nome, basta escrever: Car.find("order by name”)

> Métodos da classe PanacheEntityBase, para mais detalhes, veja o [código-fonte](https://github.com/quarkusio/quarkus/blob/master/extensions/panache/hibernate-orm-panache/runtime/src/main/java/io/quarkus/hibernate/orm/panache/PanacheEntityBase.java)

Abaixo a lista de métodos que são herdados, ao estender a classe PanacheEntityBase.

-   persist — Persiste uma entidade no banco de dados.
-   flush — Realiza o commit ou rollback de todas as transações pendentes
-   findById — Busca uma entidade por meio do ID
-   find — Lista os registros de uma entidade. (Parâmetros de Filtros e Sort são opcionais)
-   findAll — Lista todos os registros de uma entidade.
-   list — Atalho para find().list()
-   listAll — Atalho para findAll().list()
-   Count — Exibe a quantidade de registros de uma entidade. Você pode passar um parâmetro que é opcional.
-   deleteAll — Remover uma lista de objetos do banco de dados.
-   delete — Remove uma entidade, podendo utilizar uma Query (Opcional)

### Parte prática — Hands-on (Tutorial passo a passo)

Para facilitar o entendimento do Framework Panache, será criado um projeto em Quarkus + Panache e um banco de dados em Postgres, mostrando os diversos cenários em que o Panache pode auxiliar o desenvolvedor.

> Para mais detalhes do Quarkus, veja o meu artigo: [https://www.linkedin.com/pulse/tutorial-criando-um-crud-utilizando-quarkus-java-rest-da-silva-melo/](https://www.linkedin.com/pulse/tutorial-criando-um-crud-utilizando-quarkus-java-rest-da-silva-melo/)

Antes de iniciar o desenvolvimento da aplicação, é necessário atender os requisitos mínimos abaixo:

### Requisitos mínimos:

-   Você vai precisar de uma [IDE](https://en.wikipedia.org/wiki/Comparison_of_integrated_development_environments#Java) como por exemplo: [IntelliJ IDEA](https://www.jetbrains.com/idea/download/), [Eclipse](https://www.eclipse.org/downloads/), [VSCode](https://code.visualstudio.com/Download).
-   Instale a [JDK 8 or 11+](https://adoptopenjdk.net/)
-   Instale o [Apache Maven 3.5.3+](https://maven.apache.org/) ou o [Gradle](https://gradle.org/)
-   [Panache Entity](https://quarkus.io/guides/hibernate-orm-panache)
-   [Docker](https://www.docker.com/)
-   Escolha um cliente para conectar com o Banco de dados, exemplo: [DBeaver](https://dbeaver.io/download/), [MySql Workbench](https://www.linkedin.com/redir/general-malware-page?url=https%3A%2F%2Fwww%2emysql%2ecom%2Fproducts%2Fworkbench%2F), entre outros.
-   Cliente para realizar requisições REST: [Postman](https://www.getpostman.com/) ou o [Insomnia](https://insomnia.rest/download/).

### Instruções Adicionais:

-   [Instalação do Docker (Documentação oficial)](https://docs.docker.com/install/)
-   [Instalando Docker no windows](https://www.youtube.com/watch?v=OweZAewo54A): (Youtube, ESR)
-   [Instalando o Docker no Linux](https://www.youtube.com/watch?v=FTxBa7i8VMM): (Youtube: LinuxTips)
-   [Instalando o Docker no Mac:](https://www.youtube.com/watch?v=pFavwxt-4ig) (Youtube: Wellington Rogati)

### Escopo da aplicação

A partir de agora, vamos criar uma aplicação que será desenvolvida com o Quarkus, utilizando o Panache + Hibernate para persistência, CDI e JAX-RS para a API REST.

> A aplicação consiste em realizar Cadastro, Alteração, Atualização, Listagem, Paginação, Consultas Personalizadas e entre outras funcionalidades do Panache para gerenciar os Carros cadastrados no banco de dados.

// Criação do projeto em Quarkus  
  

mvn io.quarkus:quarkus-maven-plugin:1.0.1.Final:create \  
     -DprojectGroupId=br.com.car \  
     -DprojectArtifactId=quarkus-panache-car \  
     -DclassName="br.com.car.resource.CarResource" \  
     -Dpath="/cars"

Em seguida, vamos executar o projeto, através do comando:

mvn compile quarkus:dev

No navegador, acesse o endereço: [http://localhost:8080](http://localhost:8080)

![](https://cdn-images-1.medium.com/max/800/0*r2OVdywpN-i4HcTI)

### Configurando o Panache no Projeto

Adiciona as configurações abaixo no arquivo application.properties, na pasta resource na raiz do projeto.

# configure your datasource  
quarkus.datasource.url = jdbc:postgresql://localhost:5433/quarkus-panache-car  
quarkus.datasource.driver = org.postgresql.Driver  
quarkus.datasource.username = postgres  
quarkus.datasource.password = postgres  
  

# drop and create the database at startup (use `update` to only update the schema)  
quarkus.hibernate-orm.database.generation = drop-and-create

### Adicione as dependências do Panache no pom.xml.

<!-- Hibernate ORM specific dependencies -->  
<dependency>  
  <groupId>io.quarkus</groupId>  
  <artifactId>quarkus-hibernate-orm-panache</artifactId>  
</dependency>

<!-- JDBC driver dependencies -->  
<dependency>  
  <groupId>io.quarkus</groupId>  
  <artifactId>quarkus-jdbc-postgresql</artifactId>  
</dependency>

<!-- JSONB serialize JSON -->  
<dependency>  
  <groupId>io.quarkus</groupId>  
  <artifactId>quarkus-resteasy-jsonb</artifactId>  
</dependency>

> Observação: Para criar a massa de dados no início da aplicação, basta adicionar o arquivo import.sql, dentro da pasta resource do projeto.

### Executando uma instância do Postgresql no Docker

Para armazenar as informações, iniciaremos uma instância do Postgresql, utilizando o Docker, para isso, é necessário ter o Docker instalado e então executar o comando listado abaixo:

# Criando uma instância do Postgressql através do Docker

docker run --name postgres-car -e "POSTGRES_PASSWORD=postgres" -p 5433:5432 -v ~/developer/PostgreSQL:/var/lib/postgresql/data -d postgres

### Entidade Car (o modelo da aplicação)

@Entity  
public class Car extends PanacheEntityBase {

    @Id  
    @GeneratedValue(strategy = GenerationType.IDENTITY)  
    private Long id;

    private String brand;

    private String name;

    @Column(name="model_year")  
    private LocalDate modelYear;

    @Column(name="created_date_time")  
    private LocalDateTime createdDateTime;

    @Column(name="is_available_sale")  
    private Boolean isAvailableSale;

    private BigDecimal price;

// Omitido

> **_Observação_**_: O atributo Id (Chave Primária) é opcional, quando a classe estende o PanacheEntityBase_

### Testando a aplicação

Para fins didáticos, vamos separa os testes em duas partes, a primeira será utilizando os métodos do _PanacheEntityBase_, dentro da classe _Resource (EndPoint)_. A segunda parte, será utilizando uma classe _Repository + Resource(EndPoint)_.

> **Observação 1**: Outra forma seria criar uma camada de Serviço (Service) para “chamar” os métodos de uma classe [DAO](https://en.wikipedia.org/wiki/Data_access_object) ou de um Repositório.

> **Observação 2**: Sinta-se a vontade para definir o melhor padrão de sufixos de nomes, exemplo: Camada do EndPoint (API/Rest): (Controller, EndPoint, …). Camada de Negócio: (Controller, Manager, Business, ….) e assim por diante.

### Listando todos os Carros (Versão 1)

Para acessar a lista de todos os carros, basta chamar o método estático da classe Car, que é herdado a partir do PanacheEntityBase.

@Path("/cars")  
@Produces(MediaType.APPLICATION_JSON)  
public class CarResource {

    @GET  
    public List<Car> listAll() {  
        return Car.listAll();

    }

### Resultado no Postman

![](https://cdn-images-1.medium.com/max/800/0*OIv9i-epzy2csWje)

Outro forma é implementar na classe de sufixo Repository ou na classe DAO. A implementação será utilizando a classe DAO ou Repository, bastando implementar _PanacheRepository_, conforme o exemplo abaixo:

@ApplicationScoped  
public class CarRepository implements PanacheRepository<Car> {

    public List<Car> listAll() {  
        return listAll();  
    }

// omitido

A implementação na classe **CarV2Resource** (EndPoint Rest):

@Path("/cars/v2")  
@Produces(MediaType.APPLICATION_JSON)  
public class CarV2Resource {

    @Inject  
    private CarRepository carRepository;

    @GET  
    public List<Car> listAll() {  
        return carRepository.listAll();

    }

### Postman — Listar todos os veículos na versão 2 da API

O resultado é exatamente igual, quando implementado diretamente na classe do Endpoint da API.

![](https://cdn-images-1.medium.com/max/800/0*leFrmntXW9kP2G2X)

### Criando um veículo (Versão 1)

Criando um veículo, invocando o método estático da Classe Car, dentro da CarResource(EndPoint), conforme exemplo abaixo:

> A anotação @Transactional é responsável por gerenciar a transação efetuando um commit ou um rollback na transação, caso seja necessário;

@POST  
@Transactional  
public Response create(Car car) {  
    Car.persist(car);  
    return Response.ok(car).status(Response.Status.CREATED).build();

}

### Evoluindo a criação de um veículo

No endpoint CarV2Resource, basta chamar o método _save_, que está implementado no _PanacheRepository_.

Classe: CarV2Resource.java

@POST  
public Response create(Car car) {  
    Car carEntity = carRepository.save(car);  
    return Response.ok(car).status(Response.Status.CREATED).build();

}

### Postman — Resultado da inclusão de um veículo

![](https://cdn-images-1.medium.com/max/800/0*POPxWSRr0NeExNiy)

### Listando os carros por ano

// CarResource.java

@GET  
@Path("/listCarsByYear")  
public List<Car> listCarsByYear(@QueryParam("year") int year) {  
    return Car.find("year(modelYear) = :year", Parameters.with("year",   
year)).list();  
  

}

Na versão 2, a implementação utiliza o _carRepository_ e chama o método _listCarsByYear(year)_;

// CarV2Resource.java

@GET  
@Path("/listCarsByYear")  
public List<Car> listCarsByYear(@QueryParam("year") int year) {  
    return carRepository.listCarsByYear(year);

}

Implementação da lógica de pesquisa de carro por ano, na classe CarRepository.java

//CarRepository.java

public List<Car> listCarsByYear(int year) {  
    return find("year(modelYear) = :year", Parameters.with("year", year)).list();  
  

}

### Postman — Resultado da busca de veículos por ano

![](https://cdn-images-1.medium.com/max/800/0*FNvUuna9XIaED_og)

### Outros métodos:

### Listar todos os carros que estão disponíveis para venda

![](https://cdn-images-1.medium.com/max/800/0*8yMULJuTCnQDrcL6)

### Listar todos os veículos ordenados por Nome e Marca.

![](https://cdn-images-1.medium.com/max/800/0*n27bnCodpTFvFaZp)

### Listar todos os veículos passando o ano como Parâmetro

![](https://cdn-images-1.medium.com/max/800/0*jwi7ECsAKgS7pxS7)

Retornar a quantidade de veículos cadastrados

![](https://cdn-images-1.medium.com/max/800/0*_JSjiaH0JK3W4Duo)

### Listar veículos com paginação

![](https://cdn-images-1.medium.com/max/800/0*BafmuTvMIqwmo0JF)

### Atualizar veículo

![](https://cdn-images-1.medium.com/max/800/0*TnPhze5aooM4pE2J)

### Conclusão

Espero que vocês tenham gostado, sinta-se à vontade para sugerir, criticar ou elogiar. Um grande abraço e até a próxima.

### Código-Fonte

O código-fonte está disponível no endereço: [https://github.com/marcuspaulo/quarkus-panache-car](https://github.com/marcuspaulo/quarkus-panache-car)