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

Popular posts from this blog

Java 25 Features

Java Version Features

Java 8 Programs