Pular para o conteúdo principal

TP4.1 - Integração PostgreSQL com Jakarta Persistence

Migração para um Banco de Dados de Produção​

Objetivos​

Este trabalho prático permitirá que você:

  • Integrar o PostgreSQL com Spring Boot
  • Utilizar Jakarta Persistence (JPA) para persistência de dados
  • Configurar o Hibernate como ORM
  • Criar e gerenciar um banco de dados relacional
  • Entender a diferença entre Jakarta e Javax Persistence
  • Dominar a configuração com application.properties e application.yml

Tabela de Conteúdos​

  1. Revisão Rápida
  2. Adição do Banco de Dados
  3. Teste com PostgreSQL
  4. Exercício 1: Javax Persistence
  5. Exercício 2: Configuração YAML
  6. Exercício 3: Lombok
  7. Exercício 4: Recriação Automática
  8. Exercício 5: Outro Banco de Dados

1. Revisão Rápida​

Contexto​

Nos TPs anteriores, criamos uma aplicação CRUD completa com H2. Agora, vamos migrar para o PostgreSQL, um banco de dados relacional profissional adequado para produção.

Objetivos deste TP​

  1. Migrar de H2 para PostgreSQL - Passar de um banco embarcado para um banco de produção
  2. Utilizar Jakarta Persistence (JPA) - Mapear objetos Java para tabelas SQL
  3. Configurar PostgreSQL - Instalar e configurar um banco de dados profissional

Pré-requisitos​

  • TP3 (Arquitetura CRUD) concluído
  • PostgreSQL instalado (versão 12 ou superior)
  • pgAdmin ou DBeaver para gerenciar o PostgreSQL
  • Visual Studio Code com extensões Java

2. Adição do Banco de Dados​

2.1 Adição das Dependências no pom.xml​

Abra seu arquivo pom.xml e adicione as duas dependências abaixo na seção <dependencies>:

<!-- Driver PostgreSQL -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>

<!-- Spring Data JPA (inclui Jakarta Persistence) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

Explicação:

DependênciaFunção
postgresqlDriver JDBC para conectar ao PostgreSQL
spring-boot-starter-data-jpaInclui JPA, Hibernate e Spring Data

Nota: Após adicionar, o VS Code irá sugerir recarregar o projeto Maven. Aceite ou execute:

mvn clean install -DskipTests

2.2 Configuração do application.properties​

Crie ou edite o arquivo src/main/resources/application.properties:

# URL de conexão com o banco de dados
spring.datasource.url=jdbc:postgresql://localhost:5432/greeting_db?useSSL=false

# Credenciais de conexão
spring.datasource.username=postgres
spring.datasource.password=postgres

# Configuração do Hibernate
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect

# Estratégia de geração do schema
spring.jpa.hibernate.ddl-auto=create

# Exibir queries SQL (útil para desenvolvimento)
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

Explicação das propriedades:

PropriedadeDescriçãoValores possíveis
spring.datasource.urlURL de conexão JDBCFormato: jdbc:postgresql://host:port/database
spring.datasource.usernameNome de usuário do PostgreSQLPadrão: postgres
spring.datasource.passwordSenha do PostgreSQLAjuste conforme sua instalação
spring.jpa.hibernate.ddl-autoEstratégia de criação do schemanone, validate, update, create, create-drop
spring.jpa.show-sqlExibir queries SQL no consoletrue ou false

Valores de ddl-auto:

Importante: Troque greeting_db pelo nome do seu banco de dados, se necessário.

2.3 Anotação da Entidade Greeting.java​

Altere a classe Greeting.java para torná-la uma entidade JPA:

package com.example.demo;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = "greeting")
public class Greeting {

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

@Column(name = "content", nullable = false)
private String content;

// Construtor padrão (requerido pelo JPA)
public Greeting() {
}

// Construtor com parâmetros
public Greeting(Long id, String content) {
this.id = id;
this.content = content;
}

// Getters e Setters
public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}
}

Explicação das anotações:

AnotaçãoFunção
@EntityMarca a classe como entidade JPA (mapeada para uma tabela)
@Table(name = "greeting")Especifica o nome da tabela SQL
@IdMarca o campo como chave primária
@GeneratedValue(strategy = GenerationType.IDENTITY)Auto-incremento do ID
@Column(name = "content", nullable = false)Configuração da coluna SQL

Arquitetura JPA:

2.4 Criação do Repository​

Crie uma interface GreetingRepository.java no pacote com.example.demo:

package com.example.demo;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface GreetingRepository extends JpaRepository<Greeting, Long> {
// O Spring Data JPA gera automaticamente a implementação
// Métodos disponíveis: save(), findAll(), findById(), delete(), etc.
}

Métodos gerados automaticamente:

MétodoDescrição
save(Greeting g)Salvar ou atualizar
findAll()Recuperar todas as entradas
findById(Long id)Recuperar por ID
deleteById(Long id)Remover por ID
count()Contar as entradas

2.5 Modificação do Controller​

Altere o GreetingController.java para usar o repository:

package com.example.demo;

import java.util.concurrent.atomic.AtomicLong;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GreetingController {

private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();

private final GreetingRepository greetingRepository;

public GreetingController(GreetingRepository greetingRepository) {
this.greetingRepository = greetingRepository;
}

@GetMapping("/greeting")
public Greeting greeting(@RequestParam(value="name") String name) {
Greeting greeting = new Greeting(
counter.incrementAndGet(),
String.format(template, name)
);

// Salvar no banco de dados
return greetingRepository.save(greeting);
}
}

Fluxo de dados:

2.6 Criação do Banco de Dados PostgreSQL​

Opção A: Com pgAdmin​

  1. Abrir o pgAdmin

  2. Criar um usuário (opcional):

    • Clique direito em "Login/Group Roles"
    • "Create" → "Login/Group Role"
    • Aba "General": Name = postgres
    • Aba "Definition": Password = postgres
    • Aba "Privileges": Marque "Can login?" e "Create databases?"
    • Salvar
  3. Criar o banco de dados:

    • Clique direito em "Databases"
    • "Create" → "Database"
    • Database name: greeting_db
    • Owner: postgres
    • Salvar

Opção B: Com SQL (linha de comando)​

-- Criar o banco de dados
CREATE DATABASE greeting_db;

-- Criar o usuário (se necessário)
CREATE USER postgres WITH PASSWORD 'postgres';

-- Conceder privilégios
GRANT ALL PRIVILEGES ON DATABASE greeting_db TO postgres;

Para executar estes comandos:

# Windows
psql -U postgres

# macOS/Linux
sudo -u postgres psql

3. Teste com PostgreSQL​

3.1 Verificação da Configuração​

Antes de iniciar a aplicação, verifique:

Checklist:

  • PostgreSQL está iniciado
  • O banco de dados greeting_db existe
  • O usuário postgres tem os privilégios corretos
  • O arquivo application.properties está correto
  • A classe Greeting possui a anotação @Entity
  • A interface GreetingRepository foi criada
  • O GreetingController utiliza o repository

3.2 Inicialização da Aplicação​

No VS Code:

Método 1: Via Terminal​

# Limpar e compilar
mvn clean install

# Iniciar a aplicação
mvn spring-boot:run

Método 2: Via Interface​

  1. Abra GreetingApplication.java
  2. Clique em "Run" acima do método main
  3. Ou pressione F5

Logs esperados:

Hibernate: drop table if exists greeting cascade
Hibernate: create table greeting (id bigserial not null, content varchar(255) not null, primary key (id))
Started GreetingApplication in X.XXX seconds

3.3 Teste dos Endpoints​

Teste 1: Criar um greeting

http://localhost:8080/greeting?name=John

Resposta esperada:

{
"id": 1,
"content": "Hello, John!"
}

Teste 2: Criar vários greetings

http://localhost:8080/greeting?name=Alice
http://localhost:8080/greeting?name=Bob
http://localhost:8080/greeting?name=Charlie

3.4 Verificação no PostgreSQL​

Com pgAdmin:​

  1. Abra o pgAdmin
  2. Navegue: Servers → PostgreSQL → Databases → greeting_db → Schemas → public → Tables
  3. Clique direito em "greeting" → "View/Edit Data" → "All Rows"

Com SQL:​

-- Conectar ao banco
\c greeting_db

-- Exibir todas as entradas
SELECT * FROM greeting;

-- Resultado esperado:
-- id | content
-- ---+----------------
-- 1 | Hello, John!
-- 2 | Hello, Alice!
-- 3 | Hello, Bob!
-- 4 | Hello, Charlie!

3.5 Logs SQL no Console​

Graças ao spring.jpa.show-sql=true, você verá as queries SQL no console:

Hibernate: insert into greeting (content) values (?)

4. Exercício 1: Refazer com Javax Persistence​

Enunciado​

Refaça o projeto utilizando Javax Persistence ao invés de Jakarta Persistence (versão antiga do JPA).

Objetivo​

Entender a diferença entre Jakarta e Javax Persistence.

Contexto Histórico​

Instruções​

Etapa 1: Modificar pom.xml

Adicione a dependência Javax Persistence:

<!-- Adição do Javax Persistence -->
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>2.2</version>
</dependency>

Etapa 2: Modificar os imports em Greeting.java

Substitua:

import jakarta.persistence.*;

Por:

import javax.persistence.*;

Etapa 3: Classe completa com Javax

package com.example.demo;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "greeting")
public class Greeting {

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

@Column(name = "content", nullable = false)
private String content;

public Greeting() {}

public Greeting(Long id, String content) {
this.id = id;
this.content = content;
}

// Getters e Setters
public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}
}

Etapa 4: Testar

  1. Recompile: mvn clean install -DskipTests
  2. Reinicie a aplicação
  3. Verifique se tudo funciona

Perguntas para Reflexão​

  1. Qual é a principal diferença entre Javax e Jakarta Persistence?
  2. Por que Jakarta é recomendado para novos projetos?
  3. É possível misturar os dois no mesmo projeto?

5. Exercício 2: Configuração com application.yml​

Enunciado​

Converta sua configuração application.properties para o formato YAML.

Objetivo​

Dominar o formato YAML para configuração do Spring Boot.

Instruções​

Etapa 1: Remover application.properties

Remova ou renomeie o arquivo application.properties.

Etapa 2: Criar application.yml

Crie src/main/resources/application.yml:

spring:
datasource:
url: jdbc:postgresql://localhost:5432/greeting_db?useSSL=false
username: postgres
password: postgres

jpa:
hibernate:
ddl-auto: create
show-sql: true
properties:
hibernate:
jdbc:
lob:
non_contextual_creation: true
dialect: org.hibernate.dialect.PostgreSQLDialect
format_sql: true

Etapa 3: Testar

Reinicie a aplicação e verifique se tudo funciona.

Comparação​

application.properties:

spring.datasource.url=jdbc:postgresql://localhost:5432/greeting_db
spring.datasource.username=postgres
spring.jpa.hibernate.ddl-auto=create

application.yml:

spring:
datasource:
url: jdbc:postgresql://localhost:5432/greeting_db
username: postgres
jpa:
hibernate:
ddl-auto: create

Vantagens do YAML:

  • Mais legível para estruturas hierárquicas
  • Menos repetição
  • Formato moderno

6. Exercício 3: Simplificação com Lombok​

Enunciado​

Remova os getters, setters e construtores manuais utilizando Lombok.

Objetivo​

Reduzir o código boilerplate com Lombok.

Pré-requisitos​

Etapa 1: Adicionar a dependência Lombok no pom.xml

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

Etapa 2: Instalar a extensão Lombok no VS Code

  1. Extensões → Pesquisar "Lombok"
  2. Instalar "Lombok Annotations Support for VS Code"

Instruções​

Modificar Greeting.java:

package com.example.demo;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Table(name = "greeting")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Greeting {

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

@Column(name = "content", nullable = false)
private String content;

// Lombok gera automaticamente:
// - Getters
// - Setters
// - toString()
// - equals() e hashCode()
// - Construtor vazio
// - Construtor com todos os argumentos
}

Anotações Lombok:

AnotaçãoGera
@DataGetters, Setters, toString, equals, hashCode
@NoArgsConstructorConstrutor vazio
@AllArgsConstructorConstrutor com todos os campos
@GetterApenas os getters
@SetterApenas os setters

Teste​

  1. Recompile
  2. Verifique se a aplicação funciona
  3. Os métodos são gerados em tempo de compilação

7. Exercício 4: Recriação Automática do Banco​

Enunciado​

Configure a aplicação para que ela recrie automaticamente o banco de dados a cada inicialização.

Objetivo​

Entender as diferentes estratégias de gerenciamento de schema.

Instruções​

No application.properties (ou application.yml):

spring.jpa.hibernate.ddl-auto=create-drop

ou

spring:
jpa:
hibernate:
ddl-auto: create-drop

Comparação das Estratégias​

EstratégiaComportamentoUso
noneNenhuma açãoProdução
validateValida o schema sem modificarProdução
updateAtualiza o schemaDesenvolvimento
createCria o schema na inicializaçãoTestes
create-dropCria na inicialização, remove ao pararTestes unitários

Atenção​

create-drop remove todos os dados ao parar a aplicação!

Uso recomendado:

# Desenvolvimento
spring:
jpa:
hibernate:
ddl-auto: update

# Produção
spring:
jpa:
hibernate:
ddl-auto: validate

8. Exercício 5: Migração para MySQL, SQL Server ou Oracle​

Enunciado​

Refaça a integração completa com outro banco de dados.

Escolha do Banco de Dados​

Opção A: MySQL​

Dependência no pom.xml:

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>

Configuração application.properties:

spring.datasource.url=jdbc:mysql://localhost:3306/greeting_db?useSSL=false
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=update

Criação do banco no MySQL:

CREATE DATABASE greeting_db;
CREATE USER 'root'@'localhost' IDENTIFIED BY 'root';
GRANT ALL PRIVILEGES ON greeting_db.* TO 'root'@'localhost';
FLUSH PRIVILEGES;

Opção B: SQL Server​

Dependência no pom.xml:

<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<scope>runtime</scope>
</dependency>

Configuração application.properties:

spring.datasource.url=jdbc:sqlserver://localhost:1433;databaseName=greeting_db
spring.datasource.username=sa
spring.datasource.password=YourStrong@Password
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.SQLServerDialect
spring.jpa.hibernate.ddl-auto=update

Criação do banco no SQL Server:

CREATE DATABASE greeting_db;
GO

ALTER LOGIN sa WITH PASSWORD = 'YourStrong@Password';
GO

USE greeting_db;
GO

Opção C: Oracle​

Dependência no pom.xml:

<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<scope>runtime</scope>
</dependency>

Configuração application.properties:

spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe
spring.datasource.username=system
spring.datasource.password=oracle
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.Oracle12cDialect
spring.jpa.hibernate.ddl-auto=update

Criação do banco no Oracle:

CREATE USER greeting_user IDENTIFIED BY oracle;
GRANT ALL PRIVILEGES TO greeting_user;

Tabela Comparativa​

Banco de DadosPorta PadrãoDialeto HibernateDificuldade
PostgreSQL5432PostgreSQLDialectFácil
MySQL3306MySQLDialectFácil
SQL Server1433SQLServerDialectMédia
Oracle1521Oracle12cDialectDifícil

Instruções Gerais​

  1. Instale o banco de dados escolhido
  2. Altere o pom.xml com o driver correto
  3. Altere o application.properties com a configuração correta
  4. Crie o banco de dados e o usuário
  5. Recompile e teste

Resolução de Problemas​

Problema 1: Connection Refused​

Sintoma:

org.postgresql.util.PSQLException: Connection to localhost:5432 refused

Soluções:

  1. Verifique se o PostgreSQL está iniciado:

Windows:

# No Serviços, procure por PostgreSQL
services.msc

Linux:

sudo systemctl status postgresql
sudo systemctl start postgresql
  1. Verifique a porta em postgresql.conf

Problema 2: Authentication Failed​

Sintoma:

PSQLException: FATAL: password authentication failed for user "postgres"

Soluções:

  1. Verifique a senha em application.properties
  2. Redefina a senha:
ALTER USER postgres WITH PASSWORD 'nova_senha';

Problema 3: Database Does Not Exist​

Sintoma:

PSQLException: FATAL: database "greeting_db" does not exist

Solução:

Crie o banco de dados:

CREATE DATABASE greeting_db;

Problema 4: Table Already Exists​

Sintoma:

Table "greeting" already exists

Solução:

Altere a estratégia DDL:

spring.jpa.hibernate.ddl-auto=update

Problema 5: Lombok Não Funciona​

Sintoma:

error: cannot find symbol
method getId()

Soluções:

  1. Instale a extensão Lombok no VS Code
  2. Reinicie o VS Code
  3. Verifique se a dependência está no pom.xml
  4. Recompile: mvn clean install -DskipTests spring-boot:run

Perguntas de Revisão​

  1. Qual a diferença entre Jakarta e Javax Persistence?

  2. O que faz a anotação @Entity?

  3. Qual a diferença entre create, update e validate para ddl-auto?

  4. Como o Spring Data JPA gera a implementação do repository?

  5. O que faz a anotação @GeneratedValue(strategy = GenerationType.IDENTITY)?

  6. Por que é necessário um construtor vazio em uma entidade JPA?

  7. O que a anotação @Data do Lombok gera?

  8. Qual configuração usar em produção para ddl-auto?


Entregáveis​

A entregar:

  1. Código fonte completo com PostgreSQL funcional
  2. Capturas de tela mostrando:
    • A aplicação em execução
    • Os dados no pgAdmin
    • As queries SQL no console
  3. Pelo menos 2 exercícios concluídos
  4. Documento de respostas para as perguntas de revisão

Critérios de Avaliação​

CritérioPontos
Integração PostgreSQL funcional25%
Entidade Greeting corretamente anotada20%
Repository criado e utilizado15%
Dados persistidos no PostgreSQL20%
Exercícios concluídos10%
Perguntas de revisão respondidas10%
Total100%

Próximos Passos​

No próximo TP, veremos:

  • TP3: Criação de uma API CRUD completa
  • Operações: Create, Read, Update, Delete
  • Tratamento de erros
  • Validação de dados

Recursos Suplementares​

Documentação​

Tutoriais​


Voltar ao Módulo 2