Added example for JPA 2.1 stored procedure support.

This commit is contained in:
Thomas Darimont
2014-04-24 11:56:29 +02:00
committed by Oliver Gierke
parent db9ade78c7
commit 466e4d40ba
11 changed files with 305 additions and 0 deletions

54
jpa/jpa21/README.md Normal file
View File

@@ -0,0 +1,54 @@
# Spring Data JPA - JPA 2.1 example
This project contains samples of JPA 2.1 specific features of Spring Data JPA.
## Support for stored procedure execution
You can execute stored procedures either predefined using the JPA 2.1 mapping annotations or dynamically let the stored procedure definition be derived from the repository method name.
Stored procedure declaration in the database (schema.sql):
```sql
DROP procedure IF EXISTS plus1inout
/;
CREATE procedure plus1inout (IN arg int, OUT res int)
BEGIN ATOMIC
set res = arg + 1;
END
/;
```
JPA 2.1 stored procedure declaration:
```java
@Entity
@NamedStoredProcedureQuery(name = "User.plus1", procedureName = "plus1inout", parameters = {
@StoredProcedureParameter(mode = ParameterMode.IN, name = "arg", type = Integer.class),
@StoredProcedureParameter(mode = ParameterMode.OUT, name = "res", type = Integer.class) })
public class User {
@Id @GeneratedValue//
private Long id;
}
```
Spring Data JPA repository declaration to execute procedures:
```java
public interface UserRepository extends CrudRepository<User, Long> {
// Explicitly mapped to named stored procedure {@code User.plus1} in the {@link EntityManager}.
// By default, we would've try to find a procedure declaration named User.plus1BackedByOtherNamedStoredProcedure
@Procedure(name = "User.plus1")
Integer plus1BackedByOtherNamedStoredProcedure(@Param("arg") Integer arg);
// Directly map the method to the stored procedure in the database (to avoid the annotation madness on your domain classes).
@Procedure("plus1inout")
Integer derivedStoredProcedureDeclaration(Integer arg);
}
```
Calling `UserRepository.plus1BackedByOtherNamedStoredProcedure(…)` will execute the stored procedure `plus1inout` using the meta-data declared on the `User` domain class.
`UserRepository.derivedStoredProcedureDeclaration(…)` will use the stored procedure name declared in the annotation and default to positional parameter binding and expect a single output parameter of the backing stored procedure.

18
jpa/jpa21/pom.xml Normal file
View File

@@ -0,0 +1,18 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.data.examples</groupId>
<artifactId>spring-data-jpa-examples</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
</parent>
<artifactId>spring-data-jpa-jpa21</artifactId>
<name>Spring Data JPA - JPA 2.1 specific features</name>
<properties>
<spring-data-jpa.version>1.6.0.DATAJPA-455-SNAPSHOT</spring-data-jpa.version>
</properties>
</project>

View File

@@ -0,0 +1,27 @@
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.springdata.jpa.storedprocedures;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
/**
* @author Thomas Darimont
* @author Oliver Gierke
*/
@Configuration
@EnableAutoConfiguration
class StoredProcedureConfiguration {}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2013-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.springdata.jpa.storedprocedures;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.NamedStoredProcedureQuery;
import javax.persistence.ParameterMode;
import javax.persistence.StoredProcedureParameter;
/**
* Sample user class.
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
@Entity
@NamedStoredProcedureQuery(name = "User.plus1", procedureName = "plus1inout", parameters = {
@StoredProcedureParameter(mode = ParameterMode.IN, name = "arg", type = Integer.class),
@StoredProcedureParameter(mode = ParameterMode.OUT, name = "res", type = Integer.class) })
public class User {
@Id @GeneratedValue//
private Long id;
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.springdata.jpa.storedprocedures;
import javax.persistence.EntityManager;
import org.springframework.data.jpa.repository.query.Procedure;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
/**
* Simple repository interface for {@link User} instances. The interface is used to declare so called query methods,
* methods to retrieve single entities or collections of them.
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
public interface UserRepository extends CrudRepository<User, Long> {
/**
* Explicitly mapped to named stored procedure {@code User.plus1IO} in the {@link EntityManager}
*
* @see User
*/
@Procedure(name = "User.plus1")
Integer plus1BackedByOtherNamedStoredProcedure(@Param("arg") Integer arg);
/**
* Directly map the method to the stored procedure in the database (to avoid the annotation madness on your domain
* classes).
*/
@Procedure("plus1inout")
Integer derivedStoredProcedureDeclaration(Integer arg);
}

View File

@@ -0,0 +1,7 @@
/**
* Sample showing JPA 2.1 related features of Spring Data JPA.
*
* @author Thomas Darimont
* @author Oliver Gierke
*/
package example.springdata.jpa.storedprocedures;

View File

@@ -0,0 +1 @@
spring.datasource.separator=/;

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d %5p %40.40c:%4L - %m%n</pattern>
</encoder>
</appender>
<logger name="org.springframework" level="error" />
<root level="error">
<appender-ref ref="console" />
</root>
</configuration>

View File

@@ -0,0 +1,7 @@
DROP procedure IF EXISTS plus1inout
/;
CREATE procedure plus1inout (IN arg int, OUT res int)
BEGIN ATOMIC
set res = arg + 1;
END
/;

View File

@@ -0,0 +1,88 @@
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.springdata.jpa.storedprocedures;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import javax.persistence.EntityManager;
import javax.persistence.ParameterMode;
import javax.persistence.StoredProcedureQuery;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
/**
* Intergration test showing the usage of JPA 2.1 stored procedures support through Spring Data repositories.
*
* @author Thomas Darimont
* @author Oliver Gierke
*/
@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
@SpringApplicationConfiguration(classes = StoredProcedureConfiguration.class)
public class UserRepositoryIntegrationTests {
@Autowired UserRepository repository;
/**
* @see DATAJPA-455
*/
@Test
public void entityAnnotatedCustomNamedProcedurePlus1IO() {
assertThat(repository.plus1BackedByOtherNamedStoredProcedure(1), is(2));
}
/**
* @see DATAJPA-455
*/
@Test
public void invokeDerivedStoredProcedure() {
assertThat(repository.derivedStoredProcedureDeclaration(1), is(2));
}
// This is what it would look like implemented manually.
@Autowired EntityManager em;
@Test
public void plainJpa21() {
StoredProcedureQuery proc = em.createStoredProcedureQuery("plus1inout");
proc.registerStoredProcedureParameter(1, Integer.class, ParameterMode.IN);
proc.registerStoredProcedureParameter(2, Integer.class, ParameterMode.OUT);
proc.setParameter(1, 1);
proc.execute();
assertThat(proc.getOutputParameterValue(2), is((Object) 2));
}
@Test
public void plainJpa21_entityAnnotatedCustomNamedProcedurePlus1IO() {
StoredProcedureQuery proc = em.createNamedStoredProcedureQuery("User.plus1");
proc.setParameter("arg", 1);
proc.execute();
assertThat(proc.getOutputParameterValue("res"), is((Object) 2));
}
}

View File

@@ -21,6 +21,7 @@
<module>showcase</module>
<module>interceptors</module>
<module>java8</module>
<module>jpa21</module>
</modules>
<properties>