JPA进阶二

单向一对多

单向一对多是指,由一方来控制外键,多方不管理,这种方法会影响性能,不建议使用
在一方类中定义一个集合Set对象(对象要使用多态的写法,并且加上泛型),然后在其上打上注解@OneToMany表明交给一方来管理外键

@Entity
public class Product {
  @Id
  @GeneratedValue
  private Long id;
  private String name;
  
@Entity
public class ProductDir {
  @Id
  @GeneratedValue
  private Long id;
  private String name;
//表明交给一方管理
  @OneToMany
  @JoinColumn(name = "dir_id")
  // 集合映射
  private Set<Product> products = new HashSet<Product>();  

在单项一对多中,我们保存数据时,无论是先保存对放还是先报错一方,都会产生五条sql语句,这是因为交给一方管理时必须发出额外的Update语句。
单向一对多默认的是懒加载模式,我们可以设置其加载的模式。
一般Many在后面的时候都是延迟加载。

小总结:单向一对多影响性能,不建议使用,默认加载方式是延迟加载

集合映射

声明集合的时候必须使用多态写法也就是接口

   例:Set<Product> products = new HashSet<>();

因为Hibernate在创建了集合对象后是使用了它的的集合类PersistentSet来接收数据的(而不是我们写的那个HashSet)。如果我们使用接口声明(如Set),那么它的集合类PersistentSet也是实现了这个接口。所以它可以把这个类赋给Set。 但是我们使用HashSet,它们关系是平级的,不能进行转换,然后会出现代码错误

总结:声明集合的时候必须使用接口

集合映射有两种:
java.util.Set对应PersistentSet Set:无序且不可重复
java.util.List对应PersistentBag List:有序且可重复,当我们需要的存入的数据是有序且可重复的时候用List,一般是组合关系用

Set:无序,不可以重复
@OneToMany
@JoinColumn(name = "dir_id")
private Set<Product> products = new HashSet<Product>(); 

List:有序,且可重复
@OneToMany
@JoinColumn(name = "dir_id")
@OrderBy("price DESC")    //设置排序方式,售价降序   
private List<Product> products = new ArrayList<Product>();  
   总结:一般组合关系采用List,其他的时候一般用Set
   		使用List集合的时候可以使用@OrdeBy来排列顺序 

双向多对一&双向一对多

双向直接理解:你认得我(OneToMany),那我也要认识你(ManyToOne)
添加数据性能优化:
选择一:在java代码中让多方来维护关系(性能高),类似于单向多对一
选择二:在java 代码中让一方来维护关系(性能低),类似于单向一对多。
双向配置:
让一方失去对外键的管理,让多方来管理外键

OneToMany(mappedBy = "dir")表示一方的关系参照多方Prodcut属性dir来管理
@Entity//一方
@Table(name = "t_productDir")
public class ProductDir {
 @Id
 @GeneratedValue
 private Long id;
 private String name;
 @OneToMany(mappedBy = "dir")//一方失去管理外键功能
 private Set<Product> products =new HashSet();    
}

@Entity//多方
@Table(name = "t_product")
public class Product {
 @Id
 @GeneratedValue
 private  Long id;
 private  String name;
 @ManyToOne(fetch = FetchType.LAZY)
 @JoinColumn(name = "dir_id")
 private  ProductDir dir;
}  

级联操作

级联操作一般都是用在组合关系的
级联保存映射配置:@OneToMany(cascade = CascadeType.PERSIST, mappedBy = “dir”)

@OneToMany(cascade = CascadeType.PERSIST, mappedBy = "dir")
private Set<Product> products = new HashSet<Product>();

当我们保存一方时,它就会对应的将多方也保存起来

级联保存
@OneToMany(cascade = CascadeType.PERSIST, mappedBy = "dir")
1.mappedBy = "dir"表示一方的关系参照多方Prodcut属性dir来管理
2.cascade = CascadeType.PERSIST
3.必须2边都建立关系
4.entityManager.persist(dir);只能保存一方

级联删除:
1.删除一方,然后多方都删除(危险操作)
@OneToMany(cascade = CascadeType.REMOVE, mappedBy = “dir”)
2.从一方去删除一个解除关系(外键的值为null)的多方:先获取一方,再删除一个多方
@OneToMany(mappedBy = “dir”,orphanRemoval = true) 解除关联关系

 @Test
     public void testRemoveOne() throws Exception {
         EntityManager entityManager = JpaUtils.getEntityManager();
         entityManager.getTransaction().begin();
         //获取产品种类4
         ProductDir productDir = entityManager.find(ProductDir.class, 4L);
         //获取产品3
         Product product = entityManager.find(Product.class, 3L);
        // 删除所有和当前产品种类对象解除关联关系的产品对象
         productDir.getProducts().remove(product);
         entityManager.getTransaction().commit();
     }

3.从一方去删除一个解除关系(外键的值为null)的多方:先获取一方,在删除一个多方

 @Test
     public void testRemoveOne() throws Exception {
         EntityManager entityManager = JpaUtils.getEntityManager();
         entityManager.getTransaction().begin();
         //获取产品种类4
         ProductDir productDir = entityManager.find(ProductDir.class, 4L);
          // 删除所有和当前对象解除关联关系的对象
  		 productDir.getProducts().clear();
         entityManager.getTransaction().commit();
     }

强级联CascadeType.ALL:
CascadeType.ALL包含级联删除,级联保存,可是在删除的时候比较危险操作

单向多对多

意思:双向多对多就是配置两个多对多即可,就是一个演员可能有多种角色
配置信息:

@Entity//演员多方
@Table(name="t_user")
public class User {
 @Id
 @GeneratedValue
 private Long id;
 private String name;
 @ManyToMany//单向多对多
 //name为中间表名,中间表列名user_id作为user的外键,反之role_id作为role的外键
 @JoinTable(name = "t_user_role", joinColumns = { @JoinColumn(name = "user_id") },inverseJoinColumns= {
         @JoinColumn(name = "role_id") })
 private Set<Role> roles= new HashSet();
}

@Entity//角色多方
@Table(name = "t_role")
public class Role {
 @Id
 @GeneratedValue
 private Long id;
 private String name;
}

我们保存三个用户(user),两个角色(role)来进来多对多的测试
一个用户拥有多个角色
反过来一个角色也可以拥有多个用户
相当于2个多对一叠加变成多对多,多了一张中间表user_role
单向:用户可以找到多个角色
单向多对多:运用的是懒加载

双向多对多

双向多对多就是多个单向多对多
配置信息:

@Entity//演员多方
@Table(name="t_user")
public class User {
  @Id
  @GeneratedValue
  private Long id;
  private String name;
  //使用级联保存,这样保存时只用保存User即可
  @ManyToMany(cascade = CascadeType.PERSIST)//单向多对多
  //name为中间表名,中间表列名user_id作为user的外键,反之role_id作为role的外键
  @JoinTable(name = "t_user_role", joinColumns = { @JoinColumn(name = "user_id") },inverseJoinColumns= {
          @JoinColumn(name = "role_id") })
  private Set<Role> roles= new HashSet();
}

@Entity//角色多方
@Table(name = "t_role")
public class Role {
  @Id
  @GeneratedValue
  private Long id;
  private String name;
  @ManyToMany//双向多对多
  //name为中间表名,中间表列名role_id作为role的外键,反之user_id作为user的外键
  @JoinTable(name = "t_user_role", joinColumns = { @JoinColumn(name = "role_id") },inverseJoinColumns= {
          @JoinColumn(name = "user_id") })
  private Set<User> users= new HashSet();
}

双向多对多删除用户User:指定删除user1,由Hibernate自动处理,先删除中间表,再删除user1,在测试方法中直接找出user1,然后remove即可
双向多对多删除用户User:删除user1的一个角色,不能删除user1(只删除中间表)

//找到那个要删除的用户
User user = entityManager.find(User.class, 1L);
 //然后清除其角色
 user.getRoles().clear();

双向多对多修改角色:先删除再添加
双向级联删除:
配置user方,就会删除当前对象的所有role以及user本身
配置双方,就会删除所有数据
(双向级联配置删除是特别危险的)

一对一

一对一:唯一外键一对一,可以修改为一对多

@Entity
public class QQ {
  @Id
  @GeneratedValue
  private Long id;
  private String number;
  // 一对一,一个qq号码对应一个qq空间
  @OneToOne(mappedBy="qq")
  private QQZone zone;@Entity
public class QQZone {
  @Id
  @GeneratedValue
  private Long id;
  private String name;
  // 一对一,一个qq空间输入一个qq号码
  // 默认值optional = true表示qq_id可以为空;反之。。。
  @OneToOne(optional = false)
  // unique=true确保了一对一关系
  @JoinColumn(name = "qq_id", unique = true)
  private QQ qq;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值