多表之间的关系和操作多表的操作步骤

表关系

  • 一对多
  • 一对多      >>  一:主表     多:从表
  • 多对多     >>  中间表中最少应该由两个字段组成,这两个字段作为外键指向两张表的主键,又组成了联合主键

分析步骤

  1. 明确表关系
  2. 确定表关系( 描述: 外键  |  中间表 )
  3. 编写实体类,在实体类中描述表关系(包含关系)
  4. 配置映射关系

完成多表操作

一对多操作 案例:客户和联系人(一对多关系)

>> 客户:一家公司     联系人:这家公司的员工

 一个客户可以具有多个联系人,一个联系人从属于一家公司

分析步骤

  1. 明确表关系  >> 一对多关系

  2. 确定表关系,再从表上添加外键(描述: 外键 I 中间表)

  • 主表:客户表
  • 从表:联系人表

  3. 编写实体类,在实体类中描述表关系(包含关系)

  • 客户:在客户的实体类中包含一个联系人的集合
  • 联系人:在联系人的实体类中包含一个客户的对象

  4. 配置映射关系
  使用JPA注解配置一对多映射关系

操作步骤

1.引入依赖坐标,导入实体类和xml文件

2.  Customer   >> 配置客户和联系人之间的一对多关系

   @OneToMany(targetEntity = LinkMan.class) //对方实体类的字节码对象
@JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id") //name:外键的名称 referencedColumnName: 外键的取值来源
private Set<LinkMan> linkMans = new HashSet<LinkMan>();

  LinkMan   >> 配置客户和联系人之间的一对多关系

   @ManyToOne(targetEntity = Customer.class)
@JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
private Customer customer;

配置外键的过程中,配置到多的一方,就会在多的一方维护外键

3. 保存一个客户,保存一个联系人

 @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class OneToManyTest {
4 @Autowired
5 private CustomerDao customerDao;
6 @Autowired
7 private LinkManDao linkManDao;
/**
* 保存一个客户,保存一个联系人
10 * 效果:客户和联系人作为独立的数据保存到数据库中
11 * 联系人的外键为空
* 原因? >> 实体类中没有配置关系!!
*/
@Test
@Transactional //配置事务
17 @Rollback(false) //不自动回滚
public void testAdd() {
//创建一个客户,创建一个联系人
Customer customer = new Customer();
customer.setCustname("百度"); LinkMan linkMan = new LinkMan();
linkMan.setLkmName("小李");
/**
* 配置了客户到联系人的关系
* 从客户的角度上:发送两条insert语句,发送一条更新语句更新数据库(更新外键)
* 由于我们配置了客户到联系人的关系:客户可以对外键进行维护
*/

customer.getLinkMans().add(linkMan);

customerDao.save(customer);
linkManDao.save(linkMan);
}

进行改进

 /**
* 配置联系人到客户的关系(多对一)
* 只发送了两条insert语句
* 由于配置了联系人到客户的映射关系(多对一),联系人就能在保存的时候维护外键 */

linkMan.setCustomer(customer);

再次进行改进

 linkMan.setCustomer(customer);//由于配置了多的一方到一的一方的关联关系(当保存的时候,就已经对外键赋值)
customer.getLinkMans().add(linkMan);//由于配置了一的一方到多的一方的关联关系(发送一条update语句)

结果:会有一条多余的update语句 ,是由于一的一方会维护外键,发送update语句

解决的办法:只需要在一的一方放弃外键维护权即可

 @OneToMany(mappedBy = "customer")//  mappedBy:对方配置关系的属性名称,如下橙色条
private Set<LinkMan> linkMans = new HashSet<LinkMan>();对方配置关系的属性名称
@ManyToOne(targetEntity = Customer.class)
@JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
private Customer customer;
 

删除说明:当在主表中设置了放弃外键维护权,导致从表中的外键无法修改,删除时就会提示主键正在被占用不能删除。    >> 真的想删除,则使用级联删除 (实际开发中,慎用!!  >> 一对多情况下)

级联操作    >> 操作一个对象的同时操作他的关联对象

  1. 需要区分操作主体
  2. 需要在操作主体的实体类上,添加级联属性(需要添加到多表映射关系的注解上)
  3.  cascade(配置级联)

级联添加

 案例:当我保存一个客户的同时保存联系人

 Customer

 @OneToMany(mappedBy = "customer",cascade = CascadeType.ALL)  //
  • CascadeType.ALL:所有
  • MERGE:更新
  • PERSIST:保存
  • REMOVE:删除
     private Set<LinkMan> linkMans = new HashSet<LinkMan>();
 @Test
@Transactional //配置事务
@Rollback(false) //不自动回滚
public void testCascadeAdd() {
//创建一个客户,创建一个联系人
Customer customer = new Customer();
customer.setCustname("百度级联添加"); LinkMan linkMan = new LinkMan();
linkMan.setLkmName("小李级联添加"); linkMan.setCustomer(customer);//由于配置了多的一方到一的一方的关联关系(当保存的时候,就已经对外键赋值)
customer.getLinkMans().add(linkMan);//由于配置了一的一方到多的一方的关联关系(发送一条update语句) customerDao.save(customer);
}

级联删除

 案例:当我删除一个客户的同时删除此客户的所有联系人

 @Test
2 @Transactional //配置事务
@Rollback(false) //不自动回滚
public void testRemove() {
customerDao.delete(33l);
}

改进:根据客户名查询出id,再进行删除操作

 @Test
@Transactional //配置事务
@Rollback(false) //不自动回滚
public void testRemove1() {
Specification<Customer> spec=new Specification<Customer>() {
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Path<Object> custname = root.get("custname");
Predicate predicate = criteriaBuilder.equal(custname, "百度级联添加");
return predicate;
}};
Customer customerDaoOne = customerDao.findOne(spec);
Long custid = customerDaoOne.getCustid();
customerDao.delete(custid);
}

多对多操作  案例:用户和角色

1.  引入依赖坐标,导入实体类和xml文件,创建dao接口

2.  User >> 配置用户和联系人之间的一对多关系

 package cn.itcast.domain;

 import lombok.Data;

 import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Data
@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="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")}, name:外键名 referencedColumnName:参照的主表里的主键名
//inverseJoinColumns,对方对象在中间表的外键
inverseJoinColumns = {@JoinColumn(name = "sys_role_id",referencedColumnName = "role_id")} name:外键名 referencedColumnName:参照的主表里的主键名
  )  private Set<Role> roles = new HashSet<Role>();  }

3.  Role >> 配置用户和联系人之间的一对多关系

 package cn.itcast.domain;

 import lombok.Data;

 import javax.persistence.*;
import java.util.HashSet;
import java.util.Set; //@Data
@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; /*@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>(); public Long getRoleId() { return roleId; }
public void setRoleId(Long roleId) { this.roleId = roleId; }
public String getRoleName() { return roleName; }
public void setRoleName(String roleName) { this.roleName = roleName; }
public Set<User> getUsers() { return users; }
public void setUsers(Set<User> users) { this.users = users; }
}

保存一个用户,保存一个角色

Role

  @ManyToMany(mappedBy = "roles")  //配置多表关系,放弃维护权,被选择的一方放弃(因为角色被用户所选择)
private Set<User> users = new HashSet<User>();
 @Test
@Transactional
@Rollback(false) public void testAdd() {
User user = new User();
user.setUserName("小马");
user.setAge(21); Role role = new Role();
role.setRoleName("tx程序员"); //配置用户到角色关系,可以对中间表中的数据进行维护
user.getRoles().add(role);
//配置角色到用户关系
role.getUsers().add(user); userDao.save(user);
roleDao.save(role);
}

 级联添加 / 级联删除(与一对多案例类似)

 这里只给出 级联删除案例
@Transactional
@Rollback(false)
@Test
public void testCaseCadeRemove() {
User user = userDao.findOne(1l);
userDao.delete(user);
}

多表的查询

对象导航查询  :查询一个对象的同时,通过此对象查询他的关联对象

使用 jpa-day03-onetomany 项目来演示

 @Test
@Transactional no Session错误! >> 因为所有操作并没有在一个事务中进行,所以需要添加事务注解
public void testQuery1(){
//查询id为6的客户
Customer customer = customerDao.getOne(6l);
//对象导航查询,此客户下的所有联系人
Set<LinkMan> linkMans = customer.getLinkMans();
for (LinkMan linkMan : linkMans) {
System.out.println(linkMan);
} }

 默认使用的是延迟加载的形式查询的
  调用get方法并不会立即发送查询,而是在使用关联对象的时候才会差和讯延迟加载!
  修改配置,将延迟加载改为立即加载(GAGER)
    fetch (延迟加载),需要配置到多表映射关系的注解上

LinkMan

 @ManyToOne(targetEntity = Customer.class,fetch = FetchType.LAZY)
@JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
private Customer customer;
 @Test
@Transactional
public void testQuery2(){
LinkMan linkMan = linkManDao.findOne(1l);
//对象导航查询所属的语句
Customer customer = linkMan.getCustomer();
System.out.println(customer);
}

SpringDataJpa-多表操作的更多相关文章

  1. Mysql常用表操作 | 单表查询

    160905 常用表操作 1. mysql -u root -p 回车 输入密码   2. 显示数据库列表 show databases     3. 进入某数据库 use database data ...

  2. Sql Server系列:数据表操作

    表是用来存储数据和操作数据的逻辑结构,用来组织和存储数据,关系数据库中的所有数据都表现为表的形式,数据表由行和列组成.SQL Server中的数据表分为临时表和永久表,临时表存储在tempdb系统数据 ...

  3. 学习MySQL之单表操作(二)

    ##单表操作 ##创建表 CREATE TABLE t_employee( empno ), ename ), job ), MGR ), Hiredate DATE DEFAULT '0000-00 ...

  4. python——Django(ORM连表操作)

    千呼万唤始出来~~~当当当,终于系统讲了django的ORM操作啦!!!这里记录的是django操作数据库表一对多.多对多的表创建及操作.对于操作,我们只记录连表相关的内容,介绍增加数据和查找数据,因 ...

  5. mysql数据表操作&库操作

    首先登陆mysql:mysql -uroot -proot -P3306 -h127.0.0.1 查看所有的库:show databases; 进入一个库:use database; 显示所在的库:s ...

  6. SQL server基础知识(表操作、数据约束、多表链接查询)

    SQL server基础知识 一.基础知识 (1).存储结构:数据库->表->数据 (2).管理数据库 增加:create database 数据库名称 删除:drop database ...

  7. Python之Django--ORM连表操作

    一对多 class UserType(models.Model): caption = models.CharField(max_length=32) class UserInfo(models.Mo ...

  8. spark使用Hive表操作

    spark Hive表操作 之前很长一段时间是通过hiveServer操作Hive表的,一旦hiveServer宕掉就无法进行操作. 比如说一个修改表分区的操作 一.使用HiveServer的方式 v ...

  9. [SAP ABAP开发技术总结]内表操作

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  10. MFC学习 文件操作注册表操作

    c读写文件 void CFileView::OnRead() { FILE *pFile = fopen("1.txt", "r"); /*char ch[10 ...

随机推荐

  1. udp协议,进程(同步,异步)

    udp协议与进程 一.udp协议 QQ聊天室 #- sever import socket #socket.SOCK_DGRAM--->UPD协议 sever = socket.socket(t ...

  2. 教你两招用纯CSS写Tab切换

    说到Tab切换,你可能首先想到的就是使用jQuery,短短几行代码就可以轻松搞定一个Tab切换. 而今天所要分享的,是使用 0 行JS代码来实现Tab切换! 具体效果如下:   Tab切换 方法一:模 ...

  3. 克服悲伤情绪的三个P原则

    1.自责(Personalization) --不要自责 2.永久化(Permanence) --悲伤不会永远存在,一切都会过去 据科学研究发现:人遇到开心或悲伤的事情之后,心情在短期内会产生巨大的波 ...

  4. 手机号码生成器app有吗,怎么使用的呢?

    手机号码生成器app是有的,他有手机号码生成器安卓版,也有手机号码生成器苹果版的.很多人会误解他的功能以为是拿来生成号码来接验证码的,其实他不是拿来接短信的.它是用来给别人做营销找客沪的找客源的,接不 ...

  5. JSON格式日期的转换

    扒来的链接: https://blog.csdn.net/zhang33565417/article/details/99676975 感谢这位哥们儿的分享!

  6. python中可变与不可变类型的全局变量

    python中的不可变类型的全局变量如int  a=1,str  b='hello', 若需要修改必须加global申明, 而全局变量是可变类型的,如list, dict ,则直接修改list.app ...

  7. 如何解决android 通知栏不显示的问题

    android 8.0 以后的版本,在创建通知栏的时候,加了一个channelId的东西.要想在上述版本中显示通知,总共分两步 1.创建Channel if (Build.VERSION.SDK_IN ...

  8. C# 二维数组 转换成 DataTable

    C# 数据转换 Overview C# 窗体操作中,有些比较特别的操作.但是为了方便我们不得不使用一些比较特别的手段. C#中二维数组转DataTable 首先,我们看一下我对二维数组的数据处理.这次 ...

  9. 趣谈Linux操作系统学习笔记:第二十讲

    一.引子 1.计算两方面的原因 2.内存管理机制 二.独享内存空间的原理 1.会议室和物理内存的关系 和会议室一样,内存都被分成一块块儿的,都编号了号,例如3F-10就是三楼十号会议室.内存页有这样一 ...

  10. 拎壶学python3-----(1)输出与字符转换

    一.输入自己的名字打印 二.数字和字符串是不能相加的如下 怎么解决上边的问题呢? 如果是相加我们要把字符串转成数字类型如下 如果不想让他相加可以写成这样如下: ok,关于转换就先讲到这里