当前位置:   article > 正文

学习笔记——spring boot(10)数据库关联_springboot主数据源和从数据源的表怎么关联

springboot主数据源和从数据源的表怎么关联

数据库关联

在进行数据库操作的时候,总会遇到不同表之间的关联,就好比如我在Spring Security权限管理这篇博客中遇到的用户user与权限authority之间关系的关联绑定,这类表与表之间的绑定是十分重要的,所以这次就需要介绍一下hibernate关联关系注解,当然博客“码农小汪——Hibernate学习”是转载的,感谢原博主汪小哥的支持:

 

现实的世界中确实很少有孤立纯在的东西,大多都是两者之间纯在某种关系的。有单向关系 ,如只能通过老师访问学生,或者学生访问老师 ;或者双向关系: 两个都可以相互的访问。下面的关系有:

单向关系 
1-1 
1-N 
N-1 
N-N 
双向关系 
1-1 
1-N 
N-N

单向N_1关联是最多的,多个人住同一个地址,我们只需要从人这一端知道他的住址就行了,没必要知道住同一地址的用户。 为了让我们两个持久化实体关联,程序在N的一端增加持久化实体的一个属性,该属性指向引用1的那一端的关联实体。 对于N-1(不管是单向关联还是双向关联),都只需要在N的一端使用@ManyToOne修饰关联实体的属性 ,而下面的一些属性,可以通过表来记忆:

属性说明
Cascade级联操作策略CascadeType.ALL….
Fetch抓取关联实体的策略,之前说过FechType.Lazy 延迟和立即
targetEntity该属性的关联实体的类名,在默认情况下通过反射获得类名

默认情况下我们的targetEntity无需指定这个属性的。但在一些特殊的情况下,例如使用@OneToMany.@ManyToMany 修饰 1-N N-N关联的时候,关联实体集合不带泛型信息就必须指定了

 

无连接的N-1


无连接也就是不需要第三张表,维护我们的关联关系。对于N_1关联关系,我们只需要在N的一端增加一列外键即可。让外键的值记录到该属性的实体即可。Hibernate使用@JoinColumn来修饰代表关联实体的属性,用于映射底层的外键列。这种就不使用连接表了

好啦,我们看一下例子(多个人对应同一个地址):

  1. @Entity
  2. @Table(name="person_inf")
  3. public class Person
  4. {
  5.     @Id @Column(name="person_id")
  6.     @GeneratedValue(strategy=GenerationType.IDENTITY)
  7.     private Integer id;
  8.     private String name;
  9.     private int age;
  10.     // 定义该Person实体关联的Address实体
  11.     @ManyToOne(targetEntity=Address.class)
  12.     // 映射外键列,指定外键列的列名为address_id、不允许为空
  13.     @JoinColumn(name="address_id" , nullable=false)
  14.     @Cascade(CascadeType.ALL)
  15.     private Address address;
  16.     ........
  17. }

他们建立的表什么样子呢? 
person_inf 
person_id age name address_id 
address_inf 
address_id addressDetail

如何操作对象呢,因为address_id 是一个外键。如果我们保存一个Person对象在我们的表中的话,我们应该首先有一个Address 对象吧。可以是存在数据库中的,也可以才瞬态对象。我们在插入的时候级联操作,会先插入address_inf这个表中,然后才可以使用外接啦。不然会报错的,因为没有存在的外键,肯定不行啦~

  1. Session session = HibernateUtil.currentSession();
  2.     Transaction tx = session.beginTransaction();
  3.     // 创建一个Person对象
  4.     Person p = new Person();
  5.     // 创建一个瞬态的Address对象
  6.     Address a = new Address("广州天河");          
  7.     p.setName("Test");
  8.     p.setAge(21);
  9.     // 设置Person和Address之间的关联关系
  10.     p.setAddress(a);
  11.     // 持久化Person对象
  12.     session.persist(p);//级联的插入操作哦~,地址一定先于person插入数据表中,这里必须设置级联操作,不然要报错
  13.     // 创建一个瞬态的Address对象
  14.     Address a2 = new Address("上海虹口");        
  15.     // 修改持久化状态的Person对象
  16.     p.setAddress(a2);                            
  17.     tx.commit();
  18.     HibernateUtil.closeSession();

 

 

有连接的N-1


我们的关联关系的维护让第三张表来维护啦。对于大部分的N_1单向关系,只要基于外键的关联关系维护已经够了。 
如果有需要使用连接表来维护关联关系,程序可以使用连接表显示的维护这种关系,所谓连接表就是建立第三张表格来维护我们的关系就行了。使用@JoinTable

下面的是java给的例子,除了这些属性外,我们还可以指定targetEntity。指定关联的实体是哪个!也就是生成表的是哪个表所对应的实体。

  1.  @JoinTable(
  2.         name="CUST_PHONE",
  3.         //相对于当前实体的外键,的列名。 参照的列名,也就是数据表中的名字
  4.         joinColumns=
  5.             @JoinColumn(name="CUST_ID", referencedColumnName="ID"),
  6.         //这个也是个外键,只是不说当前实体里面的属性。
  7.         inverseJoinColumns=
  8.             @JoinColumn(name="PHONE_ID", referencedColumnName="ID")
  9.     )


我们来看个例子就知道啦

  1. @Entity
  2. @Table(name="person_inf")
  3. public class Person
  4. {
  5.     // 标识属性
  6.     @Id @Column(name="person_id")
  7.     @GeneratedValue(strategy=GenerationType.IDENTITY)
  8.     private Integer id;
  9.     private String name;
  10.     private int age;
  11.     // 定义该Person实体关联的Address实体
  12.     @ManyToOne(targetEntity=Address.class)
  13.     // 显式使用@JoinTable映射连接表
  14.     @JoinTable(name="person_address", // 指定连接表的表名为person_address
  15.         // 指定连接表中person_id外键列,参照到当前实体对应表的主键列
  16.         joinColumns=@JoinColumn(name="person_id"
  17.             , referencedColumnName="person_id", unique=true),
  18.         // 指定连接表中address_id外键列,参照到当前实体的关联实体对应表的主键列
  19.         inverseJoinColumns=@JoinColumn(name="address_id"
  20.             , referencedColumnName="address_id")
  21.     )
  22.     private Address address;
  23. .....
  24. }
  1. @Entity
  2. @Table(name="address_inf")
  3. public class Address
  4. {
  5.     // 标识属性
  6.     @Id @Column(name="address_id")
  7.     @GeneratedValue(strategy=GenerationType.IDENTITY)
  8.     private int addressId;
  9.     // 定义地址详细信息的成员变量
  10.     private String addressDetail;
  11. }


这里产生的表的话,以前的person的表不会改变address也不会变 
只是增加一个外表 
person_address ——table 
address_id person_id 
使用连接表维护关系

 

单向1-1关联


看上去 1-1 和N-1 差不多啊,都需要在持久化实体中增加代表关联实体的成员变量,从代码上看没得什么区别。因为N的一端和1的一端都可以直接的访问关联的实体。而无论单向的还是双向的1-1关联,都需要使用@OneToOne修饰关联实体的属性 。
有下面的级联操作,抓取属性。optional 关联关系是否可选。目标关联实体的类名targetEntity。还有个重要的 mappedBy:该属性合法的属性值为关联实体的属性名,该属性指定关联实体中的哪个属性可引用当前的实体

例子:基于外键的单向 1-1 关联,无连接表:

  1. @Entity
  2. @Table(name="person_inf")
  3. public class Person
  4. {
  5.     // 标识属性
  6.     @Id @Column(name="person_id")
  7.     @GeneratedValue(strategy=GenerationType.IDENTITY)
  8.     private Integer id;
  9.     private String name;
  10.     private int age;
  11.     // 定义该Person实体关联的Address实体
  12.     @OneToOne(targetEntity=Address.class)
  13.     // 映射名为address_id的外键列,参照关联实体对应表的addres_id主键列
  14.     @JoinColumn(name="address_id"
  15.         , referencedColumnName="address_id" , unique=true)
  16.     private Address address;
  17.   //地址肯定是独一无二的嘛,对不对!增加unique约束~
  18.     .....
  19. }


有连接表的也是差不多,理解就行了

  1. @Entity
  2. @Table(name="person_inf")
  3. public class Person
  4. {
  5.     // 标识属性
  6.     @Id @Column(name="person_id")
  7.     @GeneratedValue(strategy=GenerationType.IDENTITY)
  8.     private Integer id;
  9.     private String name;
  10.     private int age;
  11.     // 定义该Person实体关联的Address实体
  12.     @OneToOne(targetEntity=Address.class)
  13.     @JoinTable(name="person_address",
  14.         joinColumns=@JoinColumn(name="person_id"
  15.             , referencedColumnName="person_id" , unique=true),
  16.         inverseJoinColumns=@JoinColumn(name="address_id"
  17.             , referencedColumnName="address_id", unique=true)
  18.     )
  19.     private Address address;
  20.     ......
  21. }

 

 

单向的1-N


1的一端要访问N的一端,肯定的加个集合和前面的集合很相似,但是现在的集合里的元素是关联的实体啦。对于单向的1—N关联关系。只需要在1的一端加入set类型的成员变量,记录所有的关联的实体。就行了。具体怎么操作,我们慢慢的说来。一个个字的打还是可以的。增加自己的理解 

@OneToMany 
级联,抓取,目标实体,mappedBy

无连接表的单向1-N(1个人有多个住处):

  1. @Entity
  2. @Table(name="person_inf")
  3. public class Person
  4. {
  5.     @Id @Column(name="person_id")
  6.     @GeneratedValue(strategy=GenerationType.IDENTITY)
  7.     private Integer id;
  8.     private String name;
  9.     private int age;
  10.     // 定义该Person实体所有关联的Address实体,没有指定cascade属性
  11.     @OneToMany(targetEntity=Address.class)
  12.     // 映射外键列,此处映射的外键列将会添加到关联实体对应的数据表中,为啥呢?
  13.     @JoinColumn(name="person_id" , referencedColumnName="person_id")
  14.     private Set<Address> addresses
  15.         = new HashSet<>();
  16.    ........
  17.  }


这里的外键列不会增加到当前实体对应的数据表中,而是增加到,关联实体Address对应的数据表中,有点特殊!为什么。之前我们使用set集合的时候都必须在增加一个表记得?只不过这里增加到了关联实体里面去了。而不是在增加一张表~~
N的端不维护关系,没得变化~

有连接的1-N

  1. @Entity
  2. @Table(name="person_inf")
  3. public class Person
  4. {
  5.     // 标识属性
  6.     @Id @Column(name="person_id")
  7.     @GeneratedValue(strategy=GenerationType.IDENTITY)
  8.     private Integer id;
  9.     private String name;
  10.     private int age;
  11.     // 定义该Person实体所有关联的Address实体
  12.     @OneToMany(targetEntity=Address.class)
  13.     // 映射连接表为person_address
  14.     @JoinTable(name="person_address",
  15.         // 定义连接表中名为person_id的外键列,该外键列参照当前实体对应表的主键列
  16.         joinColumns=@JoinColumn(name="person_id"
  17.             , referencedColumnName="person_id"),
  18.         // 定义连接表中名为address_id的外键列,
  19.         // 该外键列参照当前实体的关联实体对应表的主键列
  20.         inverseJoinColumns=@JoinColumn(name="address_id"
  21.             , referencedColumnName="address_id", unique=true)
  22.     )
  23.     private Set<Address> addresses
  24.         = new HashSet<>();
  25. ...
  26. }


这里是1对N 1个人有多个住的地方,但是每个都是不一样的,所以要增加unique约束 
因为采用连接表了,我们的Person表中没有存在维护连接关系,可以任意的持久化操作。 
1个person 2个adress 要插入5次操作哦 
自己想想为什么?

 

单向的N-N也是需要的


@ManyToMany 
N-N关系必须需要连接表啦,和有连接的1-N相似,但是要把unique约束去掉啦~ 
直接修改啦,上面那个~

  1. @Entity
  2. @Table(name="person_inf")
  3. public class Person
  4. {
  5.     // 标识属性
  6.     @Id @Column(name="person_id")
  7.     @GeneratedValue(strategy=GenerationType.IDENTITY)
  8.     private Integer id;
  9.     private String name;
  10.     private int age;
  11.     // 定义该Person实体所有关联的Address实体
  12.     @ManyToMany(targetEntity=Address.class)
  13.     // 映射连接表为person_address
  14.     @JoinTable(name="person_address",
  15.         // 定义连接表中名为person_id的外键列,该外键列参照当前实体对应表的主键列
  16.         joinColumns=@JoinColumn(name="person_id"
  17.             , referencedColumnName="person_id"),
  18.         // 定义连接表中名为address_id的外键列,
  19.         // 该外键列参照当前实体的关联实体对应表的主键列
  20.         inverseJoinColumns=@JoinColumn(name="address_id"
  21.             , referencedColumnName="address_id")
  22.     )
  23.     private Set<Address> addresses
  24.         = new HashSet<>();
  25. ...
  26. }

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/1009379
推荐阅读
相关标签
  

闽ICP备14008679号