Spring Data JPA 实现多表操作

通过JPA框架实现多表关系

数据库中表与表之间存在着三种关系:多对多、一对多(多对一)和一对一关系。在实际开发中,我们数据库的表与表之间难免会产生联系,在操作表的时候就有可能会涉及到多张表的操作。通过使用JPA可以让我们通过操作实体类就实现对数据库表的操作,实现实体之间的关联关系。

在这里插入图片描述

环境搭建

1. 搭建Spring Data JPA的开发环境:Spring Data JPA快速入门
在这里插入图片描述

多表操作对应映射的注解说明:

@OneToMany:建立一对多的关系映

属性作用
targetEntityClass指定多的多方的类的字节码
mappedBy指定从表实体类中引用主表对象的名称
cascade指定要使用的级联操作
fetch指定是否采用延迟加载
orphanRemoval是否使用孤儿删除

@ManyToOne:建立多对一的关系

属性作用
targetEntityClass指定一的一方实体类字节码
cascade指定要使用的级联操作
fetch指定是否采用延迟加载
optional关联是否可选。如果设置为false,则必须始终存在非空关系

@ManyToMany:用于映射多对多关系

属性作用
cascade配置级联操作
fetch配置是否采用延迟加载
targetEntity配置目标的实体类。映射多对多的时候不用写

@JoinTable:针对中间表的配置

属性作用
name配置中间表的名称
joinColumns中间表的外键字段关联当前实体类所对应表的主键字段
inverseJoinColumn中间表的外键字段关联对方表的主键字段

@JoinColumn:用于定义主键字段和外键字段的对应关系

属性作用
name指定外键字段的名称
referencedColumnName指定引用主表的主键字段名称
unique是否唯一。默认值不唯一
nullable是否允许为空。默认值允许
insertable是否允许插入。默认值允许
updatable是否允许更新。默认值允许
columnDefinition列的定义信息

JPA中的一对多

确定两张表之间的关系,对于公司和联系人的关系,一个公司可以有多名员工,一个员工只能对应一个公司(不考虑兼职),公司和员工之间满足一对多关系。

在建立满足一对多关系的表时,我们习惯把一的一方称之为主表,把多的一方称之为从表。在数据库中建立一对多的关系,需要使用数据库的外键约束(从表中有一列,取值参照主表的主键)

在这里插入图片描述
在数据库中实现两张表的关系 :相关数据库代码,这里我们可以不使用数据库语句创建表,在我们运行程序时会自动生成相应的表

/*创建客户表*/
CREATE TABLE cst_customer (
  cust_id bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
  cust_name varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
  cust_source varchar(32) DEFAULT NULL COMMENT '客户信息来源',
  cust_industry varchar(32) DEFAULT NULL COMMENT '客户所属行业',
  cust_level varchar(32) DEFAULT NULL COMMENT '客户级别',
  cust_address varchar(128) DEFAULT NULL COMMENT '客户联系地址',
  cust_phone varchar(64) DEFAULT NULL COMMENT '客户联系电话',
  PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=94 DEFAULT CHARSET=utf8;

/*创建联系人表*/
CREATE TABLE cst_linkman (
  lkm_id bigint(32) NOT NULL AUTO_INCREMENT COMMENT '联系人编号(主键)',
  lkm_name varchar(16) DEFAULT NULL COMMENT '联系人姓名',
  lkm_gender char(1) DEFAULT NULL COMMENT '联系人性别',
  lkm_phone varchar(16) DEFAULT NULL COMMENT '联系人办公电话',
  lkm_mobile varchar(16) DEFAULT NULL COMMENT '联系人手机',
  lkm_email varchar(64) DEFAULT NULL COMMENT '联系人邮箱',
  lkm_position varchar(16) DEFAULT NULL COMMENT '联系人职位',
  lkm_memo varchar(512) DEFAULT NULL COMMENT '联系人备注',
  lkm_cust_id bigint(32) NOT NULL COMMENT '客户id(外键)',
  PRIMARY KEY (`lkm_id`),
  KEY `FK_cst_linkman_lkm_cust_id` (`lkm_cust_id`),
  CONSTRAINT `FK_cst_linkman_lkm_cust_id` FOREIGN KEY (`lkm_cust_id`) REFERENCES `cst_customer` (`cust_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

实体类关系建立和配置映射:

在实体类中描述出两个实体的关系,由于客户是少的一方,它应该包含多个联系人,所以实体类要体现出客户中有多个联系人的信息,代码如下:.

/**
 * 客户的实体类
 * 1.实体类与表的映射关系
 * @Entity、@Table
 * 2.类中属性与表中字段的映射关系
 * @Id
 * @GeneratedValue
 * @Column
 * 所有的注解都是使用JPA的规范提供的注解,
 * 所以在导入注解包的时候,一定要导入javax.persistence下的
 */
@Entity //声明实体类
@Table(name="cst_customer") //建立实体类和表的映射关系
public class Customer {

    @Id//声明当前私有属性为主键
    @GeneratedValue(strategy=GenerationType.IDENTITY) //配置主键的生成策略
    @Column(name="cust_id") //指定和表中cust_id字段的映射关系
    private Long custId;

    @Column(name="cust_name") //指定和表中cust_name字段的映射关系
    private String custName;

    @Column(name="cust_source")//指定和表中cust_source字段的映射关系
    private String custSource;

    @Column(name="cust_industry")//指定和表中cust_industry字段的映射关系
    private String custIndustry;

    @Column(name="cust_level")//指定和表中cust_level字段的映射关系
    private String custLevel;

    @Column(name="cust_address")//指定和表中cust_address字段的映射关系
    private String custAddress;

    @Column(name="cust_phone")//指定和表中cust_phone字段的映射关系
    private String custPhone;

    //配置客户与联系人的映射关系(一对多关系)
    /**
     * 使用注解的形式配置多表关系
     * 1.声明关系
     * @OneToMany:配置一对多关系
     * targetEntity:对方对象的字节码对象
     * 2.配置外键(中间表)
     * @JoinColumn:配置外键
     * name:外键字段名称
     * referencedColumnName:参照的主表的主键名称
     *
     * 在客户实体类上(一的一方)添加了外键配置,所以对客户而言,也具备了维护外键的作用
     */
    @OneToMany(targetEntity = LinkMan.class)
    @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
 
    /**
     * Get、Set、toString
     */
}

由于联系人是多的一方,在实体类中要体现出,每个联系人只能对应一个客户,代码如下:

/**
 * @Author: Ly
 * @Date: 2020-12-01 08:31
 * 联系人的实体类(数据模型)
 */
@Entity //声明实体类
@Table(name ="cst_linkman") //建立实体类和表的映射关系
public class LinkMan {

    @Id //声明当前私有属性为主键
    @GeneratedValue(strategy = GenerationType.IDENTITY) //配置主键的生成策略
    @Column(name = "lkm_id")
    private Long lkmId;  //联系人编号(主键)

    @Column(name = "lkm_name")
    private String lkmName;//联系人姓名

    @Column(name = "lkm_gender")
    private String lkmGender;//联系人性别

    @Column(name = "lkm_phone")
    private String lkmPhone;//联系人办公电话

    @Column(name = "lkm_mobile")
    private String lkmMobile;//联系人手机

    @Column(name = "lkm_email")
    private String lkmEmail;//联系人邮箱

    @Column(name = "lkm_position")
    private String lkmPosition;//联系人职位

    @Column(name = "lkm_memo")
    private String lkmMemo;//联系人地址信息

    /**
     * 配置联系人到用户的多对一关系
     * 使用注解的形式配置多对一关系
     * 1.配置表关系
     * 2.配置外键关系(中间表)
     * 配置外键的过程,配置到了多的一方,就会在多的一方维护外键
     */
    @ManyToOne(targetEntity = Customer.class)
    @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
    private Customer customer;

    /**
     *  Get、Set、toString
     */

} 

​​​​​​​测试一对多的操作

新建测试类:

/**
 * @Author: Ly
 * @Date: 2020-12-01 09:06
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class OneToManyTest {

    @Autowired
    private CustomerDao customerDao;

    @Autowired
    private LinkManDao linkManDao;

}

1. 测试添加数据

执行保存操作,保存一个客户和一个联系人,同时建立客户和联系人之间关联关系(双向一对多的关联关系)

@Test
@Transactional //配置事务
@Rollback(false) //设置不自动回滚
public void testAdd(){
   
    //创建一个客户,创建一个联系人
    Customer customer = new Customer();
    customer.setCustName("客户1");
    customer.setCustLevel("VIP客户");
    customer.setCustSource("网络");
    customer.setCustIndustry("商业办公");
    customer.setCustAddress("北京");
    customer.setCustPhone("111-11111111");
    
    LinkMan linkMan=new LinkMan();
   
    linkMan.setLkmName("联系人1");
    linkMan.setLkmGender("male");
    linkMan.setLkmMobile("11111111111");
    linkMan.setLkmPhone("111-11111111");
    linkMan.setLkmEmail("abc@qq.com");
    linkMan.setLkmPosition("IT讲师");
    linkMan.setLkmMemo("很厉害老师");

    /**
     * 配置了联系人到客户的关系(多对一关系)
     * 只发送了两条保存语句insert
     * 因为我们配置了联系人对客户的映射关系(多对一)
     */
    linkMan.setCustomer(customer);
    
    /**
     * 配置了客户到联系人的关系(一对多关系)
     * 从客户角度:发送两条insert语句,发送一条更新语句更新数据库(更新外键)
     * 由于我们配置了客户到联系人的关系,客户可以对外键进行维护
     */
    customer.getLinkMans().add(linkMan);
    
    /**
     * 会有一条多余的update语句
     * 由于一的一方可以维护外键,会发送update语句
     * 解决此问题:只需要在一的一方放弃维护权即可
     */
    //由于配置了多的一方到一的一方的关联关系(当保存时就已经对外键赋值)
    linkMan.setCustomer(customer);
    //由于配置了一的一方到多的一方的关联关系(发送一条update语句)
    customer.getLinkMans().add(linkMan);
    
    customerDao.save(customer);
    linkManDao.save(linkMan);
}

运行结果分析:

1.当我们只配置了多的一方到一的一方的关联关系时 linkMan.setCustomer(customer);执行了两条insert语句

2.当我们只配置了配置了一的一方到多的一方的关联关系时customer.getLinkMans().add(linkMan);执行了两条insert语句之后,还执行了update语句

3.当我们建立了双向的关联关系之后,先保存主表,再保存从表时:执行了两条insert语句之后,还执行了update语句

可以看出,在设置了双向关系之后,update语句语句是多余的,想要解决这个问题,我们可以让主表的一方放弃维护权,即修改Customer中的如下字段:

//@OneToMany(targetEntity=LinkMan.class)
//@JoinColumn(name="lkm_cust_id",referencedColumnName="cust_id")	
//设置为
@OneToMany(mappedBy="customer")

2. 测试删除数据

@Test
@Transactional
@Rollback(false)//设置为不回滚
public void testDelete() {
    customerDao.delete(1l);
}

在执行删除操作时,对于从表数据可以随时任意删除,当我们要删除主表数据数据时:

  • 1. 有从表数据
    在默认情况下,它会把外键字段置为null,然后删除主表数据。如果在数据库的表结构上,外键字段有非空约束,默认情况就会报错了。

    如果配置了放弃维护关联关系的权利,则不能删除(与外键字段是否允许为null, 没有关系)因为在删除时,它根本不会去更新从表的外键字段,这时如果还想删除,可以使用级联删除引用,在实际开发中,级联删除请慎用!(在一对多的情况下)

  • 2. 没有从表数据引用:随便删

级联操作: 指操作一个对象同时操作它的关联对象,只需要在操作主体的注解上配置cascade,就可以设置级联操作

/**
 * 放弃了外键的维护权
 * mappedBy:对方配置的属性名称(可以配置到设置多表的映射关系的注解上)
 * cascade :配置级联
 * CascadeType.ALL   所有
 * CascadeType.MERGE 更新
 * CascadeType.PERSIST  保存
 * CascadeType.REMOVE   删除
 */
@OneToMany(mappedBy = "customer",cascade = CascadeType.ALL)

JPA中的多对多

确定两张表之间的关系,对于用户和角色之间的关系,用户可以表示某一个人,它可以有很多中身份,在学校可以是学生,做兼职时可以被称作是临时工,在家里又有了子女的身份。同时对于某一个角色,也可以被多个用户拥有,每个人都可以是子女,都可以是学生,都可以是临时工。

表关系建立:

多对多的表关系建立靠的是中间表,其中用户表和中间表的关系是一对多,角色表和中间表的关系也是一对多,如下图所示:
在这里插入图片描述

实体类关系建立以及映射配置:

在实体类中描述出两个实体的关系,一个用户可以具有多个角色,所以在用户实体类中应该包含多个角色的信息,代码如下:

/**
 * @Author: Ly
 * @Date: 2020-12-01 16:57
 */
@Entity
@Table(name = "sys_user")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "user_id")
    private Long userId;

    @Column(name = "user_name")
    private String username;

    @Column(name = "user_age")
    private Integer age;

    /**
     * 配置用户到角色的多对多关系
     * 配置多对多关系
     * 1.声明表关系的配置
     *     @ManyToMany(targetEntity = Role.class)//多对多
     *     targetEntity:代表对方的实体类字节码
     * 2.配置中间表(包含两个外键)
     * @JoinTable
     * name:中间表的名称
     * joinColumns: 配置当前对象在中间表的外键
     * {@JoinColumn的数组 name:外键名,referencedColumnName 参照主表的主键名}
     * inverseJoinColumns:配置对方对象在中间表的外键
     */
    @ManyToMany(targetEntity = Role.class,cascade = CascadeType.ALL)
    @JoinTable(name = "sys_user_role",
            //joinColumns,当前对象在中间表中的外键
            joinColumns = {@JoinColumn(name = "sys_user_id",referencedColumnName = "user_id")},
            //inverseJoinColumns ,对方对象在中间表中的外键
            inverseJoinColumns = {@JoinColumn(name = "sys_role_id",referencedColumnName = "role_id")}
    )
    private Set<Role> roles=new HashSet<Role>();

    /**
     * Get、Set、toString
     */
   
}

一个角色可以赋予多个用户,所以在角色实体类中应该包含多个用户的信息,代码如下:

/**
 * @Author: Ly
 * @Date: 2020-12-01 16:58
 */
@Entity
@Table(name = "sys_role")
public class Role {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "role_id")
    private Long roleId;

    @Column(name = "role_name")
    private String roleName;

    /**
     * 配置角色到用户的多对多关系
     * 配置多对多关系
     * 1.声明表关系的配置
     * 2.配置中间表
     */
//    @ManyToMany(targetEntity = User.class)
//    @JoinTable(name = "sys_user_role",
//            //joinColumns,当前对象在中间表中的外键
//            joinColumns = {@JoinColumn(name = "sys_role_id",referencedColumnName = "role_id")},
//            //inverseJoinColumns ,对方对象在中间表中的外键
//            inverseJoinColumns = {@JoinColumn(name = "sys_user_id",referencedColumnName = "user_id")}
//    )
    @ManyToMany(mappedBy = "roles")
    private Set<User> users =new HashSet<User>();

    /**
     * Get、Set、toString
     */
}

多对多的操作:

新建测试类:

/**
 * @Author: Ly
 * @Date: 2020-12-01 09:06
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class ManyToManyTest {

    @Autowired
    private UserDao userDao;

    @Autowired
    private RoleDao roleDao;
    
}

1. 测试保存操作

保存用户和角色,用户与角色之间满足多对多关系

/**
 * 保存一个用户,保存一个角色
 */
@Test
@Transactional
@Rollback(false)
public void testAdd(){
    User user=new User();
    user.setUsername("张三");
    user.setAge(20);

    Role role=new Role();
    role.setRoleName("程序员");

    //配置用户到角色的关系,可以对中间表中的数据进行维护
    user.getRoles().add(role);
    //配置角色到用户的关系,可以对中间表中的数据进行维护
    role.getUsers().add(user);

    userDao.save(user);
    roleDao.save(role);
}

出现的问题: 在多对多(保存)中,如果双向都设置关系,意味着双方都维护中间表,都会往中间表插入数据,中间表的2个字段又作为联合主键,所以报错,主键重复,

解决保存失败的问题: 只需要在任意一方放弃对中间表的维护权即可,推荐在被动的一方放弃,配置如下:

//放弃对中间表的维护权,解决保存中主键冲突的问题
@ManyToMany(mappedBy="roles")
private Set<SysUser> users = new HashSet<SysUser>();

级联操作:

/**
 * 放弃了外键的维护权
 * mappedBy:对方配置的属性名称(可以配置到设置多表的映射关系的注解上)
 * cascade :配置级联
 * CascadeType.ALL   所有
 * CascadeType.MERGE 更新
 * CascadeType.PERSIST  保存
 * CascadeType.REMOVE   删除
 */
@ManyToMany(mappedBy = "customer",cascade = CascadeType.ALL)

测试级联操作:

/**
 * 测试级联添加(保存一个用户的同时保存关联的角色)
 */
@Test
@Transactional
@Rollback(false)
public void testCascadeAdd(){
    User user=new User();
    user.setUsername("张三");
    user.setAge(20);

    Role role=new Role();
    role.setRoleName("程序员");

    //配置用户到角色的关系,可以对中间表中的数据进行维护
    user.getRoles().add(role);
    //配置角色到用户的关系,可以对中间表中的数据进行维护
    role.getUsers().add(user);

    userDao.save(user);

}


/**
 * 测试级联删除(禁用)
 * 在多对多的删除时,双向级联删除根本不能配置
 * 如果配了的话,如果数据之间有相互引用关系,可能会清空所有数据
 */
@Test
@Transactional
@Rollback(false)
public void testCascadeRemove(){
    
    testCascadeAdd();
    //查询1号用户
    User user=userDao.findOne(1l);
    //删除1号用户
    userDao.delete(user);
}

Spring Data JPA中的多表查询

1. 对象导航查询:

对象图导航检索方式是根据已经加载的对象,导航到他的关联对象。它利用类与类之间的关系来检索对象。例如:我们通过ID查询方式查出一个客户,可以调用Customer类中的getLinkMans()方法来获取该客户的所有联系人。对象导航查询的使用要求是:两个对象之间必须存在关联关系。

新建测试类:

/**
 * @Author: Ly
 * @Date: 2020-12-01 22:05
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class ObjectQueryTest {

    @Autowired
    private CustomerDao customerDao;

    @Autowired
    private LinkManDao linkManDao;

}

查询一个客户,获取该客户下的所有联系人

//由于是在java代码中测试,为了解决no session问题,将操作配置到同一个事务中
//测试对象导航查询
@Test
@Transactional  //解决在Java代码中的no session问题
public void testQuery1(){
    //查询id为1的客户
    Customer customer=customerDao.getOne(1l);
    //对象导航查询,此客户下的所有联系人
    Set<LinkMan> linkMans = customer.getLinkMans();

    for (LinkMan linkMan:linkMans){
        System.out.println(linkMan);
    }
}

//测试对象导航查询
@Test
@Transactional  //解决在Java代码中的no session问题
public void testQuery2(){
    //查询id为1的客户
    Customer customer=customerDao.findOne(1l);
    //对象导航查询,此客户下的所有联系人
    Set<LinkMan> linkMans = customer.getLinkMans();

    for (LinkMan linkMan:linkMans){
        System.out.println(linkMan);
    }
}

对象导航查询的问题分析:

问题1:我们查询客户时,要不要把联系人查询出来?

如果我们不查的话,在用的时候还要自己写代码,调用方法去查询。如果我们查出来的,不使用时又会白白的浪费了服务器内存。

解决:采用延迟加载的思想。通过配置的方式来设定当我们在需要使用时,发起真正的查询。

/**
 * 在客户对象的@OneToMany注解中添加fetch属性
 * 		FetchType.EAGER	:立即加载
 * 		FetchType.LAZY	:延迟加载
 */
@OneToMany(mappedBy="customer",fetch=FetchType.EAGER)
private Set<LinkMan> linkMans = new HashSet<>();

问题2:我们查询联系人时,要不要把客户查询出来?

例如:查询联系人详情时,肯定会看看该联系人的所属客户。如果我们不查的话,在用的时候还要自己写代码,调用方法去查询。如果我们查出来的话,一个对象不会消耗太多的内存。而且多数情况下我们都是要使用的。

解决: 采用立即加载的思想。通过配置的方式来设定,只要查询从表实体,就把主表实体对象同时查出来

/**
 * 在联系人对象的@ManyToOne注解中添加fetch属性
 * 		FetchType.EAGER	:立即加载
 * 		FetchType.LAZY	:延迟加载
 */
@ManyToOne(targetEntity=Customer.class,fetch=FetchType.EAGER)
@JoinColumn(name="cst_lkm_id",referencedColumnName="cust_id")
private Customer customer;

2. 使用Specification查询

/**
 * Specification的多表查询
 */
@Test
public void testFind() {
	Specification<LinkMan> spec = new Specification<LinkMan>() {
		public Predicate toPredicate(Root<LinkMan> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
			//Join代表链接查询,通过root对象获取
			//创建的过程中,第一个参数为关联对象的属性名称,第二个参数为连接查询的方式(left,inner,right)
			//JoinType.LEFT : 左外连接,JoinType.INNER:内连接,JoinType.RIGHT:右外连接
			Join<LinkMan, Customer> join = root.join("customer",JoinType.INNER);
			return cb.like(join.get("custName").as(String.class),"客户1");
		}
	};
	List<LinkMan> list = linkManDao.findAll(spec);
	for (LinkMan linkMan : list) {
		System.out.println(linkMan);
	}
}
  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
### 回答1: Spring Data JPA可以通过使用@Query注解和JPQL语句来实现联合查询。在JPQL语句中,可以使用JOIN关键字来连接多个,并使用ON子句来指定连接条件。例如: @Query("SELECT u.username, p.title FROM User u JOIN u.posts p ON u.id = p.userId") List<Object[]> findUserAndPost(); 这个例子中,User和Post是两个实体类,它们之间通过userId属性建立了关联关系。通过JOIN关键字和ON子句,我们可以将两个连接起来,并查询出用户名和文章标题。最终返回的是一个Object数组,包含了查询结果中的两个字段。 除了使用@Query注解,Spring Data JPA还提供了一些方法命名规则,可以自动生成查询语句。例如,如果我们在UserRepository中定义一个方法: List<User> findByPostsTitle(String title); Spring Data JPA会自动根据方法名生成查询语句,查询所有标题为指定值的文章所属的用户。这个方法名中的“Posts”是User实体类中的一个属性,它示用户发的所有文章。通过这种方式,我们可以方便地进行多联合查询,而不需要手动编写复杂的SQL语句。 ### 回答2: Spring Data JPASpring Framework的一个模块,它提供了SpringJPA之间的集成,并支持快速开发具有CRUD功能的应用程序。在多联合查询中,Spring Data JPA可以使用JPQL或原生SQL语句来查询多个,并通过实体类的关系来建立之间的关联。下面将具体介绍如何使用Spring Data JPA进行多联合查询。 1. 使用JPQL进行多联合查询 使用JPQL进行多联合查询比使用原生SQL语句更方便,因为可以直接使用实体类和属性名来代替名和列名。 例如,我们有两个实体类:Customer和Order,它们之间是多对一的关系,即一个客户可以下多个订单。我们可以使用以下JPQL查询语句来查询所有客户及其对应的订单: ``` @Query("SELECT c, o FROM Customer c LEFT JOIN c.orders o") List<Object[]> findCustomerWithOrder(); ``` 这里使用了LEFT JOIN关键字来连接两个,LEFT JOIN示左连接,即返回左(这里是Customer)中所有数据和右(这里是Order)中匹配的数据。在SELECT语句中,我们选择了两个实体类,分别用c和o来代它们,并将它们放在一个数组中返回。这样就可以查询到所有客户及其对应的订单。 2. 使用原生SQL语句进行多联合查询 如果使用JPQL不能满足需求,也可以使用原生SQL语句来进行多联合查询。这时需要使用EntityManager来执行SQL语句。 例如,我们有两个:Customer和Order,它们之间的关系同上。我们可以使用以下SQL语句来查询所有客户及其对应的订单: ``` SELECT c.*, o.* FROM customer c LEFT JOIN orders o ON c.id = o.customer_id ``` 在EntityManager中,可以使用createNativeQuery方法来创建原生SQL语句的查询对象,以及setParameter方法来设置查询参数(如果有的话)。例如: ``` String sql = "SELECT c.*, o.* FROM customer c LEFT JOIN orders o ON c.id = o.customer_id"; Query query = entityManager.createNativeQuery(sql); List<Object[]> resultList = query.getResultList(); ``` 这里使用了Query.getResultList方法来返回结果集,它返回的是一个包含多个数组的列,每个数组对应一行查询结果。数组中的元素按照SELECT语句的顺序排列。 总结 Spring Data JPA提供了方便的方法来进行多联合查询,可以使用JPQL或原生SQL语句来查询多个,并通过实体类之间的关系建立之间的关联。使用JPQL可以更方便地查询,而使用原生SQL语句可以更灵活地满足各种查询需求。 ### 回答3: Spring Data JPASpring Data项目的一部分,它通过JPA规范提供了ORM解决方案。在关系型数据库中,一个数据库通常由多张组成,而在开发过程中,我们经常需要对这些进行查询、修改、删除等操作,如果我们需要进行多查询,该如何实现呢? Spring Data JPA 提供了多种方式实现联合查询,下面我们对这些方式进行一一介绍。 1.通过JPA的关联查询实现联合 JPA提供了两种形式的关联查询:内部关联查询和左外关联查询,这两种关联查询可以满足大部分复杂查询的需求。 内部关联查询:通过@Table注解中@TableJoinColumn属性或@JoinColumn注解,将两个实体类之间的关联关系定义在Java类中。定义完关联关系后,可以通过JPQL或Spring Data JPA提供的函数查询方法实现联合查询。 左外关联查询:Spring Data JPA还提供了@Query注解的方式,开发者可以自行编写JPQL或SQL语句实现联合查询,并通过@Query注解进行绑定。 2.通过Criteria API实现联合 Criteria API是JPA提供的查询语言的一种形式,它允许开发人员通过程序生成查询语句,而不必编写具体的SQL或JPQL语句。使用Criteria API时,只需要将实体类的基本属性与关联属性设定好之后,生成一个CriteriaBuilder对象,就可以构建复杂的查询语句。 3.通过Spring Data JPA提供的命名查询实现联合 Spring Data JPA提供了命名查询的方式,命名查询是通过在Repository中定义方法的名称和方法的输入参数来实现的。命名查询是一个声明式的查询,开发者可以指定所需的查询字符串和返回值。 总而言之,Spring Data JPA提供了多种方式实现联合查询,并且具有简洁、高效、易维护等特点,开发者可以根据需求选择最合适的方式来实现联合查询。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙源lll

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值