JPA与存储过程的完美结合

server/2025/2/26 12:15:01/

在现代的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)
IStemp_count NUMBER := -1;
BEGINSELECT COUNT(*) INTO temp_count FROM PERSON WHERE ID = person_id_in;IF temp_count > 0 THENINSERT 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;ELSEmsg_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
BEGINOPEN 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 Setterspublic 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;}@Overridepublic String toString() {return "Person{" +"id=" + id +", firstName='" + firstName + '\'' +", lastName='" + lastName + '\'' +", address='" + address + '\'' +'}';}@Overridepublic 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);}@Overridepublic 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 idTypedQuery<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 procedureStoredProcedureQuery 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.ppmy.cn/server/170742.html

相关文章

音视频容器格式

音视频容器格式是存储和封装音视频流、字幕、元数据等信息的文件格式。容器格式决定了音视频的组织方式和播放方式&#xff0c;不同的容器格式适用于不同的用途和平台。以下是一些常见的音视频容器格式的详细介绍&#xff1a; 1. MP4 (.mp4) 介绍&#xff1a; MP4 是最常见的…

网络应用层之HTTPS

前言 HTTPS 是什么 HTTP 协议内容都是按照文本的方式明文传输的. 这就导致在传输过程中出现⼀些被篡改的情况. HTTPS 也是⼀个应用层协议, 是在 HTTP 协议的基础上引入了⼀个加密层SSL/TLS, 负责对HTTP进行握手协商和数据的加密解密. 此时交给传输层的数据都是经过加密的, 数…

“零信任+AI”将持续激发网络安全领域技术创新活力

根据Forrester的报告&#xff0c;到2025年&#xff0c;AI软件市场规模将从2021年的330亿美元增长到640亿美元&#xff0c;网络安全将成为AI支出增长最快的细分市场。当前&#xff0c;零信任供应侧企业已经开始尝试使用AI赋能零信任&#xff0c;未来&#xff0c;零信任与AI的结合…

终端指令(补充)和shell

1.终端指令&#xff08;补充&#xff09;思维导图 2.shell思维导图

Maven 依赖的深入理解(一)

一、Maven 依赖初相识 在 Java 项目开发的广袤天地里&#xff0c;Maven 就如同一位得力的助手&#xff0c;而 Maven 依赖则是其核心的 “魔法棒”&#xff0c;为项目构建带来了前所未有的便利与高效。随着项目规模的日益壮大&#xff0c;依赖的管理变得愈发复杂&#xff0c;手…

聊一聊提升测试用例覆盖率需要从哪几方面入手?

目录 一、需求覆盖&#xff1a;确保无遗漏 二、代码覆盖&#xff1a;工具辅助优化 三、路径覆盖&#xff1a;逻辑深度遍历 四、边界值覆盖&#xff1a;防御性测试设计 五、异常场景覆盖&#xff1a;模拟真实故障 六、兼容性覆盖&#xff1a;全环境验证 七、性能覆盖&…

Java入门基础、JDK安装和配置

参考笔记&#xff1a;2024年最新版IntelliJ IDEA下载安装过程&#xff08;含Java环境搭建&#xff09;-CSDN博客 目录 1.什么是程序 2.Java特性 3.Java_JDK介绍 3.1 Java运行机制及流程 3.2 JVM 3.3 JDK基本介绍 3.4 JRE基本介绍 4.JDK下载与配置&#xff08;Windows&…

【STL专题】优先级队列priority_queue的使用和模拟实现,巧妙利用仿函数解决优先级

欢迎来到 CILMY23的博客 &#x1f3c6;本篇主题为&#xff1a;优先级队列priority_queue的使用和模拟实现&#xff0c;巧妙利用仿函数解决优先级 &#x1f3c6;个人主页&#xff1a;CILMY23-CSDN博客 &#x1f3c6;系列专栏&#xff1a; C | C语言 | 数据结构与算法 | Linux…