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.