JPA与存储过程的完美结合

news/2025/2/25 4:20:49

在现代的Java开发中,JPA(Java Persistence API)已经成为ORM(对象关系映射)的主流选择之一。它不仅简化了数据库操作,还提供了强大的功能来与数据库交互。今天,我们将深入探讨如何通过@NamedStoredProcedureQuery注解在JPA中使用数据库存储过程,并通过一个完整的示例来展示其强大的功能。

一、@NamedStoredProcedureQuery简介

@NamedStoredProcedureQuery是JPA提供的一个注解,用于在实体类中声明可复用的数据库存储过程。通过这个注解,我们可以将存储过程与实体类关联起来,并在代码中方便地调用这些存储过程。

以下是@NamedStoredProcedureQuery注解的主要属性:

  • name:用于引用的存储过程名称。
  • procedureName数据库中存储过程的实际名称。
  • parameters:存储过程的参数信息,包括参数名、类型和模式(如IN、OUT、INOUT、REF_CURSOR)。
  • resultClasses:存储过程返回的结果集对应的Java类。
  • resultSetMappings:存储过程返回的结果集映射。
  • hints:查询的属性和提示。

二、示例:使用Oracle存储过程

为了更好地理解@NamedStoredProcedureQuery的使用,我们将通过一个完整的示例来展示如何在JPA中调用Oracle数据库的存储过程。这个示例包括两个存储过程:一个用于将记录从主表移动到历史表,另一个用于查询历史表中的记录。

1. 数据库准备

首先,我们需要在Oracle数据库中创建表和存储过程。以下是SQL脚本:

DROP TABLE PERSON;
DROP SEQUENCE SQ_PERSON;
CREATE TABLE PERSON (
    ID NUMBER(19),
    FIRST_NAME VARCHAR(255),
    LAST_NAME VARCHAR(255),
    ADDRESS VARCHAR(255),
    PRIMARY KEY (ID)
);
CREATE SEQUENCE SQ_PERSON MINVALUE 1 START WITH 1 INCREMENT BY 1 CACHE 10;

DROP TABLE PERSON_HISTORY;
CREATE TABLE PERSON_HISTORY AS SELECT * FROM PERSON WHERE 1=0;

CREATE OR REPLACE PROCEDURE MOVE_TO_HISTORY(person_id_in IN NUMBER, msg_out OUT VARCHAR2)
IS
    temp_count NUMBER := -1;
BEGIN
    SELECT COUNT(*) INTO temp_count FROM PERSON WHERE ID = person_id_in;
    IF temp_count > 0 THEN
        INSERT INTO PERSON_HISTORY SELECT * FROM PERSON WHERE ID = person_id_in;
        msg_out := 'Person with id: ' || person_id_in || ' moved to History table. Update count: ' || SQL%ROWCOUNT;
        DELETE FROM PERSON WHERE ID = person_id_in;
    ELSE
        msg_out := 'No Person Exists with id: ' || person_id_in;
    END IF;
END;
/

CREATE OR REPLACE PROCEDURE FETCH_PERSON_HISTORY(history_cursor OUT SYS_REFCURSOR)
IS
BEGIN
    OPEN history_cursor FOR SELECT * FROM PERSON_HISTORY;
END;
/
2. 实体类定义

接下来,我们定义一个Person实体类,并使用@NamedStoredProcedureQuery注解来声明存储过程。

import javax.persistence.*;
import java.util.Objects;

@Entity
@NamedStoredProcedureQuery(
        name = Person.NamedQuery_MoveToHistory,
        procedureName = "MOVE_TO_HISTORY",
        parameters = {
                @StoredProcedureParameter(name = "person_id_in", type = Long.class, mode = ParameterMode.IN),
                @StoredProcedureParameter(name = "msg_out", type = String.class, mode = ParameterMode.OUT)
        }
)
@NamedStoredProcedureQuery(
        name = Person.NamedQuery_FetchFromHistory,
        procedureName = "FETCH_PERSON_HISTORY",
        resultClasses = {Person.class},
        parameters = {
                @StoredProcedureParameter(name = "history_cursor", type = void.class, mode = ParameterMode.REF_CURSOR)
        }
)
public class Person {
    public static final String NamedQuery_MoveToHistory = "moveToHistory";
    public static final String NamedQuery_FetchFromHistory = "fetchFromHistory";

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SQ_PERSON")
    @SequenceGenerator(sequenceName = "SQ_PERSON", allocationSize = 1, name = "SQ_PERSON")
    private long id;

    @Column(name = "FIRST_NAME")
    private String firstName;

    @Column(name = "LAST_NAME")
    private String lastName;

    private String address;

    // Getters and Setters
    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", address='" + address + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return id == person.id &&
                Objects.equals(firstName, person.firstName) &&
                Objects.equals(lastName, person.lastName) &&
                Objects.equals(address, person.address);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, firstName, lastName, address);
    }
}
3. 调用存储过程

最后,我们通过EntityManager调用这些存储过程。以下是主类的代码:

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.StoredProcedureQuery;
import java.util.List;

public class ExampleMain {
    private static EntityManagerFactory entityManagerFactory =
            Persistence.createEntityManagerFactory("example-unit");

    public static void main(String[] args) {
        try {
            reset();
            persistEntities();
            findAllEmployeeEntities();
            movePersonToHistoryByName("Dana");
            movePersonToHistoryByName("Mike");
            fetchPersonHistory();
        } finally {
            entityManagerFactory.close();
        }
    }

    private static void fetchPersonHistory() {
        System.out.println("-- Fetching person History --");
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        StoredProcedureQuery procedureQuery =
                entityManager.createNamedStoredProcedureQuery(Person.NamedQuery_FetchFromHistory);
        procedureQuery.execute();
        @SuppressWarnings("unchecked")
        List<Person> resultList = procedureQuery.getResultList();
        resultList.forEach(System.out::println);
    }

    private static void movePersonToHistoryByName(String name) {
        System.out.printf("-- Moving person to history table name: %s --%n", name);
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        // get person id
        TypedQuery<Long> query = entityManager
                .createQuery("SELECT p.id FROM Person p WHERE p.firstName = :firstName", Long.class);
        query.setParameter("firstName", name);
        Long personId = query.getSingleResult();
        // stored procedure
        StoredProcedureQuery procedureQuery = entityManager
                .createNamedStoredProcedureQuery(Person.NamedQuery_MoveToHistory);
        entityManager.getTransaction().begin();
        procedureQuery.setParameter("person_id_in", personId);
        procedureQuery.execute();
        Object msg_out = procedureQuery.getOutputParameterValue("msg_out");
        System.out.println("Out msg= " + msg_out);
        entityManager.getTransaction().commit();
    }

    private static void findAllEmployeeEntities() {
        System.out.println("-- all Person entities -  --");
        EntityManager em = entityManagerFactory.createEntityManager();
        TypedQuery<Person> query = em.createQuery("SELECT p from Person p", Person.class);
        List<Person> resultList = query.getResultList();
        resultList.forEach(System.out::println);
        em.close();
    }

    private static void persistEntities() {
        Person person1 = new Person();
        person1.setFirstName("Dana");
        person1.setLastName("Whitley");
        person1.setAddress("464 Gorsuch Drive");

        Person person2 = new Person();
        person2.setFirstName("Robin");
        person2.setLastName("Cash");
        person2.setAddress("64 Zella Park");

        Person person3 = new Person();
        person3.setFirstName("Chary");
        person3.setLastName("Mess");
        person3.setAddress("112 Yellow Hill");

        Person person4 = new Person();
        person4.setFirstName("Rose");
        person4.setLastName("Kantata");
        person4.setAddress("2736 Kooter Lane");

        Person person5 = new Person();
        person5.setFirstName("Mike");
        person5.setLastName("Togglie");
        person5.setAddress("111 Cool Dr");

        EntityManager em = entityManagerFactory.createEntityManager();
        em.getTransaction().begin();
        em.persist(person1);
        em.persist(person2);
        em.persist(person3);
        em.persist(person4);
        em.persist(person5);
        em.getTransaction().commit();
        em.close();
    }

    private static void reset() {
        EntityManager em = entityManagerFactory.createEntityManager();
        em.getTransaction().begin

http://www.niftyadmin.cn/n/5864969.html

相关文章

安全见闻5

今天学了Windows操作系统和驱动程序的相关知识 Windows注册表 注册表是windows系统中具有层次结构的核心数据库 储存的数据对windows 和Windows上运行的应用程序和服务至关重要。注册表时帮助windows控制硬件、软件、用户环境和windows界面的一套数据文件。 打开注册表编辑器…

搭建Docker Harbor仓库

搭建 Docker Harbor 仓库是一个常见的需求&#xff0c;Harbor 是一个企业级的 Docker 镜像仓库&#xff0c;提供了镜像管理、用户权限控制、漏洞扫描等功能。以下是详细的搭建步骤&#xff1a; 1. 环境准备 操作系统&#xff1a;Ubuntu 20.04 或更高版本&#xff08;或其他 Li…

AxiosError: Network Error

不知怎么的&#xff0c;项目还在开发阶段&#xff0c;之前还好好的&#xff0c;玩儿了两天再一打开发现页面无法显示数据了&#xff0c;报错如下&#xff1a; 我以为是后端出问题了&#xff0c;但是后端控制台无报错&#xff0c;又用postman测试了一下&#xff0c;可以获取到数…

npm使用了代理,但是代理软件已经关闭导致创建失败

如果在关闭前打开了vscode&#xff0c;此时vscode中的终端没有刷新&#xff0c;就会出现这个问题&#xff0c;最开始会一直转圈圈&#xff0c;直到超时&#xff0c;然后出现该报错 ❯ npm create vuelatest npm error code ECONNREFUSED npm error syscall connect npm error …

Qt QTreeWidget 总结

Qt QTreeWidget 总结 1. 概述 QTreeWidget 是 Qt 中用于显示树形结构的控件&#xff0c;继承自 QTreeView&#xff0c;但提供了更简单的接口。适合展示层级数据&#xff08;如文件目录、组织结构&#xff09;。每个节点是 QTreeWidgetItem 对象&#xff0c;支持文本、图标、复…

《鸿蒙开发-答案之书》获取视频第一帧和视频时间

《鸿蒙开发-答案之书》获取视频第一帧和视频时间 /*** 获取视频信息**let result await MySightUtil.getSightInfo(this.sightUri);*let base64 : string result[0];*let duration : number result[1]** param uri 视频地址* returns 第一个数据是缩略图 base64 字符串&…

通过AI辅助生成PPT (by quqi99)

作者&#xff1a;张华 发表于&#xff1a;2025-02-23 版权声明&#xff1a;可以任意转载&#xff0c;转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明(http://blog.csdn.net/quqi99) 问题 媳妇需要将一个pdf文件中的某些部分做成PPT课件&#xff0c;我在想是…

【Windows系统node_modules删除失败(EPERM)问题解析与应对方案】

Windows系统node_modules删除失败(EPERM)问题解析与应对方案 问题现象 当开发者尝试删除Node.js项目的node_modules目录时&#xff0c;常会遇到如下错误提示&#xff1a; [Error: EPERM: operation not permitted, unlink D:\project\...\esbuild.exe] {errno: -4048,code: …