Spring Data JPA多表关联查询及存储过程调用实现咨询
在Spring Boot中实现关联表数据的自定义展示
前提假设
假设你的三张表对应以下实体(根据实际结构调整):
- 表A → 实体
A:字段id(主键)、name - 表B → 实体
B:字段id(主键)、tname - 表C → 实体
C:字段id(主键)、idA(外键关联A.id)、idB(外键关联B.id)、subtype(对应展示的Subtype列)
首先需要创建一个DTO/投影接口来接收自定义查询结果,因为要返回非实体的自定义列:
方式1:使用DTO类
public class DisplayDTO { private String name; private String type; private String subtype; // 用于JPQL构造查询的构造函数 public DisplayDTO(String name, String type, String subtype) { this.name = name; this.type = type; this.subtype = subtype; } // getter和setter方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getSubtype() { return subtype; } public void setSubtype(String subtype) { this.subtype = subtype; } }
方式2:使用投影接口(更简洁)
public interface DisplayProjection { String getName(); // 对应查询结果的name列 String getType(); // 对应查询结果的type列 String getSubtype(); // 对应查询结果的subtype列 }
1. 编写查询语句获取数据
Spring Data JPA支持JPQL和原生SQL两种查询方式,任选其一即可。
1.1 JPQL查询(推荐,与数据库无关)
在C的Repository接口中添加查询方法:
import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import java.util.List; public interface CRepository extends CrudRepository<C, Long> { // 使用DTO接收结果 @Query("SELECT new com.example.yourpackage.DisplayDTO(a.name, b.tname, c.subtype) " + "FROM C c " + "JOIN A a ON c.idA = a.id " + "JOIN B b ON c.idB = b.id") List<DisplayDTO> getDisplayData(); // 或者使用投影接口 @Query("SELECT a.name AS name, b.tname AS type, c.subtype AS subtype " + "FROM C c " + "JOIN A a ON c.idA = a.id " + "JOIN B b ON c.idB = b.id") List<DisplayProjection> getDisplayDataViaProjection(); }
1.2 原生SQL查询(适合复杂SQL或数据库特定语法)
同样在CRepository中添加:
@Query(value = "SELECT a.name AS name, b.tname AS type, c.subtype AS subtype " + "FROM c_table c " + "JOIN a_table a ON c.id_a = a.id " + "JOIN b_table b ON c.id_b = b.id", nativeQuery = true) List<DisplayDTO> getDisplayDataNative(); // 投影接口也适用原生SQL @Query(value = "SELECT a.name AS name, b.tname AS type, c.subtype AS subtype " + "FROM c_table c " + "JOIN a_table a ON c.id_a = a.id " + "JOIN b_table b ON c.id_b = b.id", nativeQuery = true) List<DisplayProjection> getDisplayDataNativeViaProjection();
2. 通过存储过程实现操作
2.1 第一步:在数据库中创建存储过程
以MySQL为例,执行以下SQL创建存储过程:
DELIMITER // CREATE PROCEDURE GetDisplayData() BEGIN SELECT a.name AS name, b.tname AS type, c.subtype AS subtype FROM c_table c JOIN a_table a ON c.id_a = a.id JOIN b_table b ON c.id_b = b.id; END // DELIMITER ;
(其他数据库如Oracle、PostgreSQL的存储过程语法略有不同,需对应调整)
2.2 第二步:在Spring Boot中调用存储过程
有两种常用方式:
方式1:通过Spring Data JPA Repository调用
首先在C实体类上添加存储过程注解:
import javax.persistence.NamedStoredProcedureQuery; import javax.persistence.Entity; import javax.persistence.Table; @NamedStoredProcedureQuery( name = "C.getDisplayData", // 自定义名称,需与Repository方法的@Procedure参数一致 procedureName = "GetDisplayData", // 数据库中存储过程的名称 resultClasses = DisplayDTO.class // 返回结果的DTO类 ) @Entity @Table(name = "c_table") public class C { // 实体字段定义,例如: // @Id // @GeneratedValue(strategy = GenerationType.IDENTITY) // private Long id; // private Long idA; // private Long idB; // private String subtype; }
然后在CRepository中添加调用方法:
import org.springframework.data.jpa.repository.Procedure; public interface CRepository extends CrudRepository<C, Long> { @Procedure(name = "C.getDisplayData") List<DisplayDTO> getDisplayDataFromProcedure(); }
方式2:通过EntityManager手动调用
适合需要更灵活控制的场景,在Service层实现:
import org.springframework.stereotype.Service; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.StoredProcedureQuery; import java.util.ArrayList; import java.util.List; @Service public class CService { @PersistenceContext private EntityManager entityManager; public List<DisplayDTO> getDisplayDataViaProcedure() { // 创建存储过程查询 StoredProcedureQuery query = entityManager.createStoredProcedureQuery("GetDisplayData"); // 获取结果并映射到DTO List<Object[]> resultList = query.getResultList(); List<DisplayDTO> dtoList = new ArrayList<>(); for (Object[] result : resultList) { DisplayDTO dto = new DisplayDTO( (String) result[0], // name (String) result[1], // type (String) result[2] // subtype ); dtoList.add(dto); } return dtoList; } }
内容的提问来源于stack exchange,提问作者csa
相关产品推荐
相关产品推荐

