JPA
JPA
Stored Procedure
Q. Calling a Stored Procedure in JPA?
In JPA (Java Persistence API), calling a stored procedure is typically done using the `@NamedStoredProcedureQuery` annotation or the `EntityManager` API.
Here's a breakdown of how it works, especially in the context of Spring Boot + JPA, which you're already fluent with:
1. Using `@NamedStoredProcedureQuery` (Annotation-Based)
Step-by-step setup:
a. Define the stored procedure in your entity:
```java
@Entity
@NamedStoredProcedureQuery(
name = "User.getUserByEmail",
procedureName = "get_user_by_email",
parameters = {
@StoredProcedureParameter(mode = ParameterMode.IN, name = "email", type = String.class),
@StoredProcedureParameter(mode = ParameterMode.OUT, name = "user_id", type = Long.class)
}
)
public class User {
@Id
private Long id;
private String email;
// other fields...
}
```
b. Call it via `EntityManager`:
```java
StoredProcedureQuery query = entityManager
.createNamedStoredProcedureQuery("User.getUserByEmail")
.setParameter("email", "user1@example.com");
Long userId = (Long) query.getOutputParameterValue("user_id");
```
2. Using `EntityManager.createStoredProcedureQuery()` (Dynamic Approach)
Example:
```java
StoredProcedureQuery query = entityManager
.createStoredProcedureQuery("get_user_by_email")
.registerStoredProcedureParameter("email", String.class, ParameterMode.IN)
.registerStoredProcedureParameter("user_id", Long.class, ParameterMode.OUT)
.setParameter("email", "sudhamsh@example.com");
query.execute();
Long userId = (Long) query.getOutputParameterValue("user_id");
```
3. Spring Data JPA Repository Integration (Optional)
If you're using Spring Data JPA, you can also define stored procedure calls directly in your repository:
```java
public interface UserRepository extends JpaRepository<User, Long> {
@Procedure(name = "User.getUserByEmail")
Long getUserByEmail(@Param("email") String email);
}
```
Bonus: Calling Procedures with Result Sets
If your stored procedure returns a result set (e.g., a list of users), you can map it like this:
```java
StoredProcedureQuery query = entityManager
.createStoredProcedureQuery("get_all_users", User.class);
List<User> users = query.getResultList();
```
> Would you like to scaffold a mini Spring Boot app that demonstrates stored procedure calls with JWT-secured endpoints and Swagger docs?
Q. Step-By-Step guide to calling a stored procedure using JPA in a Spring Boot application.
This approach is clean, secure, and aligns well with your microservice architecture and JWT-authenticated APIs.
Step-by-Step: Calling Stored Procedure in JPA
Step 1: Create the Stored Procedure in Your Database
```sql
CREATE PROCEDURE get_user_by_email (
IN email_input VARCHAR(255),
OUT user_id BIGINT
)
BEGIN
SELECT id INTO user_id FROM users WHERE email = email_input;
END;
```
Step 2: Annotate Your Entity with `@NamedStoredProcedureQuery`
```java
@Entity
@NamedStoredProcedureQuery(
name = "User.getUserByEmail",
procedureName = "get_user_by_email",
parameters = {
@StoredProcedureParameter(mode = ParameterMode.IN, name = "email_input", type = String.class),
@StoredProcedureParameter(mode = ParameterMode.OUT, name = "user_id", type = Long.class)
}
)
public class User {
@Id
private Long id;
private String email;
// other fields...
}
```
Step 3: Call the Procedure via `EntityManager`
```java
@Autowired
private EntityManager entityManager;
public Long fetchUserIdByEmail(String email) {
StoredProcedureQuery query = entityManager
.createNamedStoredProcedureQuery("User.getUserByEmail")
.setParameter("email_input", email);
query.execute();
return (Long) query.getOutputParameterValue("user_id");
}
```
Step 4: Optional — Integrate with Spring Data JPA Repository
```java
public interface UserRepository extends JpaRepository<User, Long> {
@Procedure(name = "User.getUserByEmail")
Long getUserByEmail(@Param("email_input") String email);
}
```
Step 5: Secure It with JWT and Expose via REST Controller
```java
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserRepository userRepository;
@GetMapping("/id-by-email")
public ResponseEntity<Long> getUserId(@RequestParam String email) {
Long userId = userRepository.getUserByEmail(email);
return ResponseEntity.ok(userId);
}
}
```
Step 6: Test It with Swagger or Postman
- Endpoint: `GET /api/users/id-by-email?email=sudhamsh@example.com`
- JWT token in Authorization header
- Response: `200 OK` with user ID
EntityManager
In JPA (especially within Spring Boot), the `EntityManager` is made available through the JPA provider (like Hibernate) and is managed by the Spring container.
Here's a step-by-step breakdown of how it's wired and accessed:
How `EntityManager` Becomes Available in JPA
1. JPA Configuration via Spring Boot Starter
When you include this dependency:
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
```
Spring Boot auto-configures:
- JPA provider (Hibernate by default)
- `EntityManagerFactory`
- Transaction manager
- Datasource connection
2. Spring Boot Auto-Wiring of `EntityManager`
You can inject it directly into any Spring-managed bean:
```java
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
@Service
public class UserService {
@PersistenceContext
private EntityManager entityManager;
// or with constructor injection
public UserService(EntityManager entityManager) {
this.entityManager = entityManager;
}
}
```
- `@PersistenceContext` ensures it's tied to the current transaction.
- Spring wraps the native `EntityManager` with a proxy for transaction safety.
3. Behind the Scenes: EntityManagerFactory
Spring Boot internally creates an `EntityManagerFactory` bean:
```java
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
// configured with DataSource, JPA properties, etc.
}
```
This factory produces `EntityManager` instances per transaction or request scope.
4. Transactional Context
To use `EntityManager` safely, annotate your methods with `@Transactional`:
```java
@Transactional
public void updateUser(Long id, String email) {
User user = entityManager.find(User.class, id);
user.setEmail(email);
entityManager.merge(user);
}
```
Spring ensures:
- Transaction boundaries
- Lazy loading
- Flush/commit behavior
Bonus: Accessing Hibernate Features
You can unwrap the native Hibernate session:
```java
Session session = entityManager.unwrap(Session.class);
```
Useful for:
- Stored procedures
- Batch operations
- Native queries
Composite Key
Q. How to create a composite key in Java Side?
In Java (specifically using JPA), you can create a composite key using either `@IdClass` or `@EmbeddedId`.
Both approaches allow you to define multiple fields as a primary key for an entity.
Option 1: Using `@IdClass`
This method separates the key class from the entity.
Step-by-step:
1. Create a key class:
```java
import java.io.Serializable;
public class AccountId implements Serializable {
private String accountNumber;
private String accountType;
// Constructors, equals(), and hashCode()
}
```
2. Define the entity:
```java
import javax.persistence.*;
@Entity
@IdClass(AccountId.class)
public class Account {
@Id
private String accountNumber;
@Id
private String accountType;
private String ownerName;
// Getters and setters
}
```
Option 2: Using `@EmbeddedId`
This method embeds the key class directly into the entity.
Step-by-step:
1. Create an embeddable key class:
```java
import java.io.Serializable;
import javax.persistence.*;
@Embeddable
public class BookId implements Serializable {
private String title;
private String language;
// Constructors, equals(), and hashCode()
}
```
2. Define the entity:
```java
import javax.persistence.*;
@Entity
public class Book {
@EmbeddedId
private BookId id;
private String author;
// Getters and setters
}
```
Best Practices
- Always implement `equals()` and `hashCode()` in your key class.
- Make the key class `Serializable`.
- Use `@Column` annotations inside the key class if needed.
- Avoid mixing `@IdClass` and `@EmbeddedId` in the same entity.
> Would you like a hands-on simulation using Spring Boot or Hibernate to see how composite keys behave in real-world microservices?
Comments
Post a Comment