Um guia para procedimentos armazenados com JPA

Um guia para procedimentos armazenados com JPA

1. Introdução

Neste tutorial rápido, exploraremos o uso de procedimentos armazenados na Java Persistence API (JPA).

2. Configuração do Projeto

2.1. Configuração do Maven

Primeiro precisamos definir as seguintes dependências em nossopom.xml:

  • javax.javaee-api - uma vez que inclui a API JPA

  • uma implementação da API JPA - neste exemplo, usaremosHibernate, masEclipseLink também seria uma alternativa OK

  • a Banco de dadosMySQL


    7.0
    11.2.0.4
    5.1.38


    
        javax
        javaee-api
        ${jee.version}
        provided
    
    
        org.hibernate
        hibernate-entitymanager
        ${hibernate.version}
    
    
        mysql
        mysql-connector-java
        ${mysql.version}
    

2.2. Definição de Unidade de Persistência

A segunda etapa é a criação do arquivosrc/main/resources/META-INF/persistence.xml - que contém as definições da unidade de persistência:




    
        org.hibernate.jpa.HibernatePersistenceProvider
        com.example.jpa.model.Car
        
            
            
            
            
            
            
        
    

Todas as propriedades do Hibernate definidas não são necessárias se você se referir a um JNDI DataSource (ambientes JEE):

java:jboss/datasources/JpaStoredProcedure

2.3. Script de Criação de Tabela

Vamos agora criar umTable ( CAR ) - com três atributos:ID, MODELeYEAR:

CREATE TABLE `car` (
  `ID` int(10) NOT NULL AUTO_INCREMENT,
  `MODEL` varchar(50) NOT NULL,
  `YEAR` int(4) NOT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

A suposição era, é claro, que o esquema e as permissões do banco de dados já estão em vigor.

2.4. Criação de procedimento armazenado no banco de dados

O último passo antes de pular para o código java é a criação do procedimento armazenado em nosso banco de dados MySQL:

DELIMITER $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `FIND_CAR_BY_YEAR`(in p_year int)
begin
SELECT ID, MODEL, YEAR
    FROM CAR
    WHERE YEAR = p_year;
end
$$
DELIMITER ;

3. O procedimento armazenado JPA

Agora estamos prontos para usar o JPA para se comunicar com o banco de dados e executar o procedimento armazenado que definimos.

Depois de fazer isso, também seremos capazes de iterar os resultados como umList deCar.

3.1. A EntidadeCar

Abaixo da entidadeCar que deve ser mapeada para a tabela de banco de dadosCAR pelo Entity Manager.

Observe que também estamos definindo nosso procedimento armazenado diretamente na entidade usando a anotação@NamedStoredProcedureQueries:

@Entity
@Table(name = "CAR")
@NamedStoredProcedureQueries({
  @NamedStoredProcedureQuery(
    name = "findByYearProcedure",
    procedureName = "FIND_CAR_BY_YEAR",
    resultClasses = { Car.class },
    parameters = {
        @StoredProcedureParameter(
          name = "p_year",
          type = Integer.class,
          mode = ParameterMode.IN) })
})
public class Car {

    private long id;
    private String model;
    private Integer year;

    public Car(String model, Integer year) {
        this.model = model;
        this.year = year;
    }

    public Car() {
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID", unique = true, nullable = false, scale = 0)
    public long getId() {
        return id;
    }

    @Column(name = "MODEL")
    public String getModel() {
        return model;
    }

    @Column(name = "YEAR")
    public Integer getYear() {
        return year;
    }

    // standard setter methods
}

3.2. Acessando o Banco de Dados

Agora, com tudo definido e no lugar, vamos escrever alguns testes usando JPA para executar o procedimento.

Vamos recuperar todos osCars em um determinadoyear: __

public class StoredProcedureTest {

    private static EntityManagerFactory factory = null;
    private static EntityManager entityManager = null;

    @BeforeClass
    public static void init() {
        factory = Persistence.createEntityManagerFactory("jpa-db");
        entityManager = factory.createEntityManager();
    }

    @Test
    public void findCarsByYearWithNamedStored() {
        StoredProcedureQuery findByYearProcedure =
          entityManager.createNamedStoredProcedureQuery("findByYearProcedure");

        StoredProcedureQuery storedProcedure =
          findByYearProcedure.setParameter("p_year", 2015);

        storedProcedure.getResultList()
          .forEach(c -> Assert.assertEquals(new Integer(2015), ((Car) c).getYear()));
    }

    @Test
    public void findCarsByYearNoNamedStored() {
        StoredProcedureQuery storedProcedure =
          entityManager
            .createStoredProcedureQuery("FIND_CAR_BY_YEAR",Car.class)
            .registerStoredProcedureParameter(1, Integer.class, ParameterMode.IN)
            .setParameter(1, 2015);

        storedProcedure.getResultList()
          .forEach(c -> Assert.assertEquals(new Integer(2015), ((Car) c).getYear()));
    }

}

Observe que no segundo teste,we’re no longer using the stored procedure we defined on the entity. Em vez disso, estamos definindo o procedimento do zero.

Isso pode ser muito útil quando você precisa usar procedimentos armazenados, mas não tem a opção de modificar suas entidades e recompilá-las.

4. Conclusão

Neste tutorial, discutimos o procedimento armazenado com a API Java Persistence.

O exemplo usado neste artigo está disponível comosample project in GitHub.