关于JpaRepository的关联查询和@Query查询

目录
  • 一 pom
  • 二 启动类
  • 三 配置文件
  • 四 新建数据库
  • 五 实体类
    • 1 Clazz
    • 2 Student
  • 六 控制器
  • 七 Repository层
    • 1 ClazzRepository
    • 2 StudentRepository
  • 八 Service层
  • 九 测试

一 pom

<project xmlns="http://maven.apache.org/POM/4.0.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0  http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.fkit</groupId>
     <artifactId>springdatajpaquerytest</artifactId>
     <version>0.0.1-SNAPSHOT</version>
     <packaging>jar</packaging>
     <name>springdatajpaquerytest</name>
     <url>http://maven.apache.org</url>
     <!-- spring-boot-starter-parent是Spring Boot的核心启动器,  包含了自动配置、日志和YAML等大量默认的配置,大大简化了我们的开发。
           引入之后相关的starter引入就不需要添加version配置, spring  boot会自动选择最合适的版本进行添加。 -->
     <parent>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-parent</artifactId>
           <version>2.0.0.RELEASE</version>
           <relativePath />
     </parent>
     <properties>
           <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
           <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
           <java.version>1.8</java.version>
     </properties>
     <dependencies>
           <!-- 添加spring-boot-starter-web模块依赖 -->
           <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
           </dependency>
           <!-- 添加spring-boot-starter-thymeleaf模块依赖 -->
           <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-thymeleaf</artifactId>
           </dependency>
           <!-- 添加MySQL依赖 -->
           <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
           </dependency>
           <!-- 添加Spring Data JPA依赖 -->
           <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
           </dependency>
           <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <scope>test</scope>
           </dependency>
     </dependencies>
</project>

二 启动类

package org.fkit.springdatajpaquerytest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class App
{
    public static void main( String[] args )
    {
        // SpringApplication 用于从main方法启动Spring应用的类。
        SpringApplication.run(App.class, args);
    }
}

三 配置文件

########################################################
### \u6570\u636E\u6E90\u4FE1\u606F\u914D\u7F6E
########################################################
# \u6570\u636E\u5E93\u5730\u5740
spring.datasource.url=jdbc:mysql://localhost:3306/springdatajpaquery
# \u7528\u6237\u540D
spring.datasource.username=root
# \u5BC6\u7801
spring.datasource.password=
# \u6570\u636E\u5E93\u9A71\u52A8
spring.datasource.driverClassName=com.mysql.jdbc.Driver
#  \u6307\u5B9A\u8FDE\u63A5\u6C60\u4E2D\u6700\u5927\u7684\u6D3B\u8DC3\u8FDE\u63A5\u6570.
spring.datasource.max-active=20
#  \u6307\u5B9A\u8FDE\u63A5\u6C60\u6700\u5927\u7684\u7A7A\u95F2\u8FDE\u63A5\u6570\u91CF.
spring.datasource.max-idle=8
#  \u6307\u5B9A\u5FC5\u987B\u4FDD\u6301\u8FDE\u63A5\u7684\u6700\u5C0F\u503C
spring.datasource.min-idle=8
#  \u6307\u5B9A\u542F\u52A8\u8FDE\u63A5\u6C60\u65F6\uFF0C\u521D\u59CB\u5EFA\u7ACB\u7684\u8FDE\u63A5\u6570\u91CF
spring.datasource.initial-size=10
########################################################
### JPA\u6301\u4E45\u5316\u914D\u7F6E
########################################################
# \u6307\u5B9A\u6570\u636E\u5E93\u7684\u7C7B\u578B
spring.jpa.database=MySQL
#  \u6307\u5B9A\u662F\u5426\u9700\u8981\u5728\u65E5\u5FD7\u4E2D\u663E\u793Asql\u8BED\u53E5
spring.jpa.show-sql=true
#  \u6307\u5B9A\u81EA\u52A8\u521B\u5EFA|\u66F4\u65B0|\u9A8C\u8BC1\u6570\u636E\u5E93\u8868\u7ED3\u6784\u7B49\u914D\u7F6E\uFF0C\u914D\u7F6E\u6210update
#  \u8868\u793A\u5982\u679C\u6570\u636E\u5E93\u4E2D\u5B58\u5728\u6301\u4E45\u5316\u7C7B\u5BF9\u5E94\u7684\u8868\u5C31\u4E0D\u521B\u5EFA\uFF0C\u4E0D\u5B58\u5728\u5C31\u521B\u5EFA\u5BF9\u5E94\u7684\u8868
spring.jpa.hibernate.ddl-auto=update
# Naming strategy
# \u6307\u5B9A\u547D\u540D\u7B56\u7565
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy
# \u6307\u5B9A\u6570\u636E\u5E93\u65B9\u8A00
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect

四 新建数据库

springdatajpaquery

五 实体类

1 Clazz

package org.fkit.springdatajpaquerytest.bean;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name="tb_clazz")
public class Clazz implements Serializable{

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int code ;
    private String name ;
    // 班级与学生是一对多的关联
    @OneToMany(
               fetch=FetchType.LAZY,
               targetEntity=Student.class,
               mappedBy="clazz"
            )
    private Set<Student> students = new HashSet<>();

    public Clazz() {

    }
    // 班级对象
    public Clazz(String name) {
        this.name = name;
    }
    public int getCode() {
        return code;
    }
    public void setCode(int code) {
        this.code = code;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Set<Student> getStudents() {
        return students;
    }
    public void setStudents(Set<Student> students) {
        this.students = students;
    }
}

2 Student

package org.fkit.springdatajpaquerytest.bean;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name="tb_student")
public class Student implements Serializable{
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String name ;
    private String address ;
    private int age ;
    private char sex;
    // 学生与班级是多对一的关系,这里配置的是双向关联
    @ManyToOne(fetch=FetchType.LAZY,
            targetEntity=Clazz.class
            )
    @JoinColumn(name="clazzId",referencedColumnName="code")
    private Clazz clazz ;
    public Student() {

    }
    public Student(String name, String address, int age, char sex,
            Clazz clazz) {
        super();
        this.name = name;
        this.address = address;
        this.age = age;
        this.sex = sex;
        this.clazz = clazz;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public char getSex() {
        return sex;
    }
    public void setSex(char sex) {
        this.sex = sex;
    }
    public Clazz getClazz() {
        return clazz;
    }
    public void setClazz(Clazz clazz) {
        this.clazz = clazz;
    }
}

六 控制器

package org.fkit.springdatajpaquerytest.controller;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.fkit.springdatajpaquerytest.bean.Clazz;
import org.fkit.springdatajpaquerytest.bean.Student;
import org.fkit.springdatajpaquerytest.service.SchoolService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/student")
public class StudentController {

    // 注入ShcoolService
    @Resource
    private SchoolService schoolService;
    @RequestMapping("/save")
    public String save() {

        Clazz clazz1 = new Clazz("疯狂java开发1班");
        Clazz clazz2 = new Clazz("疯狂java开发2班");
        // 保存班级对象数据
        List<Clazz> clazzs = new ArrayList<>();
        clazzs.add(clazz1);
        clazzs.add(clazz2);
        schoolService.saveClazzAll(clazzs);

        Student swk = new Student("孙悟空","广州",700,'男',clazz1);
        Student zzj = new Student("蜘蛛精","广州",700,'女',clazz1);
        Student nmw = new Student("牛魔王","广州",500,'男',clazz2);

        List<Student> students = new ArrayList<>();
        students.add(swk);
        students.add(zzj);
        students.add(nmw);
        schoolService.saveStudentAll(students);
        return "保存学生对象成功";
    }
    /**
     * 查询某个班级下所有的学生姓名,年龄,性别
     * @param clazzName
     * @return
     */
    @RequestMapping("/getClazzStus")
    public List<Map<String, Object>> getClazzStus(String clazzName){
        return schoolService.getStusByClazzName(clazzName);
    }
    /**
     * 查询某个班级下所有的学生姓名,性别
     * @param clazzName
     * @return
     */
    @RequestMapping("/findNameAndSexByClazzName")
    public List<Map<String, Object>> findNameAndSexByClazzName(String clazzName){
        return schoolService.findNameAndSexByClazzName(clazzName);
    }
    /**
     * ,查询某个班级下某种性别的所有学生的姓名
     * @param clazzName
     * @return
     */
    @RequestMapping("/findNameByClazzNameAndSex")
    public List<String> findNameByClazzNameAndSex(String clazzName ,Character sex){
        return schoolService.findNameByClazzNameAndSex(clazzName ,sex);
    }
    /**
     * 查询某个学生属于哪个班级
     * @param clazzName
     * @return
     */
    @RequestMapping("/findClazzNameByStuName")
    public String findClazzNameByStuName(String stuName){
        return schoolService.findClazzNameByStuName(stuName);
    }
    /**
     * 删除某个学生对象
     * @param clazzName
     * @return
     */
    @RequestMapping("/deleteStuByStuName")
    public String deleteStuByStuName(String stuName){
        return "删除数据:"+schoolService.deleteStuByStuName(stuName);
    }
}

七 Repository层

1 ClazzRepository

package org.fkit.springdatajpaquerytest.repository;
import org.fkit.springdatajpaquerytest.bean.Clazz;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ClazzRepository extends JpaRepository<Clazz, Integer> {
}

2 StudentRepository

package org.fkit.springdatajpaquerytest.repository;
import java.util.List;
import java.util.Map;
import org.fkit.springdatajpaquerytest.bean.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface StudentRepository extends JpaRepository<Student, Integer> {

    /**
     * 根据班级名称查询这个班级下所有的学生信息
     * 相当于JPQL语句: select s from Student s where s.clazz.name = ?1
     * @param clazzName
     * @return
     */
    List<Student> findByClazz_name(String clazzName);

    /**
     * @Query写法
     * 根据班级名称查询这个班级下所有的学生信息
     * ?1此处使用的是参数的位置,代表的是第一个参数
     * 此写法与 findByClazz_name方法实现的功能完全一致
     * */
    @Query("select s from Student s where s.clazz.name = ?1")
    List<Student> findStudentsByClazzName(String clazzName);
    /**
     * 使用@Query注解的形式,查询某个班级下所有学生的姓名和性别
     * @param clazzName
     * @return
     */
    @Query("select new Map(s.name as name , s.sex as sex) "
            + "from Student s where s.clazz.name = ?1")
    List<Map<String, Object>> findNameAndSexByClazzName(String clazzName);

    /**
     *  使用@Query注解的形式,查询某个班级下某种性别的所有学生的姓名
     *  上面方法是用的是参数的位置来查询的,Spring Data JPA中还支持用
     *  名称来匹配查询使用格式 “:参数名称” 引用
     * @param clazzName
     * @return
     */
    @Query("select s.name from Student s "
            + "where s.clazz.name = :clazzName and s.sex = :sex ")
    List<String> findNameByClazzNameAndSex(@Param("clazzName")String clazzName , @Param("sex")char sex);
    /**
     *  使用@Query注解的形式,查询某个学生属于哪个班级
     * @param stuName
     * @return
     */
    @Query("select c.name from Clazz c inner join c.students s "
            + "where s.name = ?1 ")
    String findClazzNameByStuName(String stuName);
    /**
     * 执行更新查询,使用@Query与@Modifying可以执行更新操作
     * 例如删除牛魔王这个学生
     * */
    @Modifying
    @Query("delete from Student s where s.name = ?1")
    int deleteStuByStuName(String stuName);
}

八 Service层

package org.fkit.springdatajpaquerytest.service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.fkit.springdatajpaquerytest.bean.Clazz;
import org.fkit.springdatajpaquerytest.bean.Student;
import org.fkit.springdatajpaquerytest.repository.ClazzRepository;
import org.fkit.springdatajpaquerytest.repository.StudentRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class SchoolService {

    // 注入数据访问层接口对象
    @Resource
    private StudentRepository studentRepository;
    @Resource
    private ClazzRepository clazzRepository;

    @Transactional
    public void saveClazzAll(List<Clazz> clazzs) {
        clazzRepository.saveAll(clazzs);
    }
    @Transactional
    public void saveStudentAll(List<Student> students) {
        studentRepository.saveAll(students);
    }

    public List<Map<String, Object>> getStusByClazzName(String clazzName) {
        // 使用"_" 和 @Query查询方式结果一致
        List<Student> students = studentRepository.findByClazz_name(clazzName);
//        List<Student> students = studentRepository.findStudentsByClazzName(clazzName);
        List<Map<String, Object>>  results = new ArrayList<>();
        // 遍历查询出的学生对象,提取姓名,年龄,性别信息
        for(Student student:students){
            Map<String , Object> stu = new HashMap<>();
            stu.put("name", student.getName());
            stu.put("age", student.getAge());
            stu.put("sex", student.getSex());
            results.add(stu);
        }
        return results;
    }
    public List<Map<String, Object>> findNameAndSexByClazzName(String clazzName) {
        return studentRepository.findNameAndSexByClazzName(clazzName);
    }
    public List<String> findNameByClazzNameAndSex(
            String clazzName, char sex) {
        return studentRepository.findNameByClazzNameAndSex(clazzName, sex);
    }
    public String findClazzNameByStuName(String stuName) {
        return studentRepository.findClazzNameByStuName(stuName);
    }
    @Transactional
    public int deleteStuByStuName(String stuName) {
        return studentRepository.deleteStuByStuName(stuName);
    }
}

九 测试

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

时间: 2021-11-23

让JPA的Query查询接口返回Map对象的方法

在JPA 2.0 中我们可以使用entityManager.createNativeQuery()来执行原生的SQL语句. 但当我们查询结果没有对应实体类时,query.getResultList()返回的是一个List<Object[]>.也就是说每行的数据被作为一个对象数组返回. 常见的用法是这样的: public void testNativeQuery(){ Query query = entityManager.createNativeQuery("select id, n

JPA如何使用nativequery多表关联查询返回自定义实体类

目录 JPA nativequery多表关联查询返回自定义实体类 JPA多表关联的实现方式 优缺点对比 使用sql并返回自定义实体类 JPA多表关联动态查询(自定义sql语句) 实体类 注解解释 测试类 打印结果 TestVo实体接收类 JPA nativequery多表关联查询返回自定义实体类 JPA官方推荐的多表关联查询使用不便,接触的有些项目可能会使用JPA 做简单查询,Mybaits做复杂查询.所以想要寻找一种好用的解决方案. JPA多表关联的实现方式 1.使用Specification

SpringBoot Data JPA 关联表查询的方法

SpringBoot Data JPA实现 一对多.多对一关联表查询 开发环境 IDEA 2017.1 Java1.8 SpringBoot 2.0 MySQL 5.X 功能需求 通过关联关系查询商店Store中所有的商品Shop,商店对商品一对多,商品对商店多对一,外键 store_id存在于多的一方.使用数据库的内连接语句. 表结构 tb_shop tb_store 实体类,通过注解实现 1.商店类Store.java package com.gaolei.Entity; import ja

Mongodb实现的关联表查询功能【population方法】

本文实例讲述了Mongodb实现的关联表查询功能.分享给大家供大家参考,具体如下: Population MongoDB是非关联数据库.但是有时候我们还是想引用其它的文档.这就是population的用武之地. Population是从其它文档替换文档中的特定路径.我们可以迁移一个单一的文件,多个文件,普通对象,多个普通的对象,或从查询中返回的所有对象 populate 方法 populate 方法可以用在 document 上. model 上或者是 query 对象上,这意味着你几乎可以在任

MyBatis学习教程(五)-实现关联表查询方法详解

一.一对一关联  1.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数据 创建一张教师表和班级表,这里我们假设一个老师只负责教一个班,那么老师和班级之间的关系就是一种一对一的关系. CREATE TABLE teacher( t_id INT PRIMARY KEY AUTO_INCREMENT, t_name VARCHAR() ); CREATE TABLE class( c_id INT PRIMARY KEY AUTO_INCREMENT, c_name VAR

Yii中CGridView关联表搜索排序方法实例详解

本文实例讲述了Yii中CGridView关联表搜索排序方法.分享给大家供大家参考.具体实现方法如下: 在Yii CGridView 关联表搜索排序实现方法有点复杂,今天看了一老外写的了篇游戏,下面我整理一下与各位朋友分享一下,相信会对大家Yii框架的学习有所帮助. 首先,检查你的blog demo里的protectedmodelsComment.php,确保Comment模型有一个search的方法,如果没有,就用gii生成一个,我下载到的blog demo里倒是没有. 然后,写代码的时间到了,

SQLServer批量更新两个关联表数据的方法

本文实例讲述了SQLServer批量更新两个关联表数据的方法.分享给大家供大家参考,具体如下: 方式1: UPDATE a SET WtNo=b.NO from WT_Task a INNER JOIN WT_BasicInformation b ON a.WtId=b.ID; 方式2: UPDATE a SET a.WtNo=b.NO FROM WT_Task a,WT_BasicInformation b WHERE a.WtId=b.ID; 希望本文所述对大家SQL Server数据库程序

Spring Data JPA 建立表的联合主键

最近遇到了一个小的问题,就是怎么使用 Spring Data JPA 建立表的联合主键?然后探索出了下面的两种方式. 第一种方式: 第一种方式是直接在类属性上面的两个字段都加上 @Id 注解,就像下面这样,给 stuNo 和 stuName 这两个字段加上联合主键: @Entity @Table(name = "student") public class Student { @Id @Column(name = "stu_no", nullable = false

Django ManyToManyField 跨越中间表查询的方法

1.在 django 表中用到了 manytomany 生成了中间表 pyclub_article_column from django.db import models # Create your models here. class Column(models.Model): id = models.AutoField(u'序号',primary_key=True,auto_created=True) name = models.CharField(u'名字',max_length=100)

thinkPHP框架实现多表查询的方法

本文实例讲述了thinkPHP框架实现多表查询的方法.分享给大家供大家参考,具体如下: 我们可以将两个表连起来一起查询数据,我现在有两张表,一个是feedback表和member表,如图: 总目录: 上代码: $where = array(); $where['meiyepin_feedback.member_id'] = "1"; $Model = M('feedback'); $a = $Model ->join('meiyepin_member ON meiyepin_fe

Spring Data JPA实现动态查询的两种方法

前言 一般在写业务接口的过程中,很有可能需要实现可以动态组合各种查询条件的接口.如果我们根据一种查询条件组合一个方法的做法来写,那么将会有大量方法存在,繁琐,维护起来相当困难.想要实现动态查询,其实就是要实现拼接SQL语句.无论实现如何复杂,基本都是包括select的字段,from或者join的表,where或者having的条件.在Spring Data JPA有两种方法可以实现查询条件的动态查询,两种方法都用到了Criteria API. Criteria API 这套API可用于构建对数据

详解Spring Data JPA动态条件查询的写法

我们在使用SpringData JPA框架时,进行条件查询,如果是固定条件的查询,我们可以使用符合框架规则的自定义方法以及@Query注解实现. 如果是查询条件是动态的,框架也提供了查询接口. JpaSpecificationExecutor 和其他接口使用方式一样,只需要在你的Dao接口继承即可(官网代码). public interface CustomerRepository extends CrudRepository<Customer, Long>, JpaSpecification