1.单向一对多
映射配置
//一方
@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
// 必须配置外键id,否则会多生成一张表,形成多对多的关系
@JoinColumn(name = "dir_id")
// 建议实例化,用的时候不需要在实例化,这里和单向多对一要求不同
private Set<Product> products = new HashSet<Product>();
保存代码
public void persist() throws Exception {
// 一方
ProductDir dir = new ProductDir();
dir.setName("类型1");
// 多方
Product product = new Product();
product.setName("产品1");
Product product2 = new Product();
product2.setName("产品2");
// 连接关系(只能由一方建立到多方的关系)
dir.getProducts().add(product);
dir.getProducts().add(product2);
EntityManager entityManager = JPAUtils.getEntityManager();
entityManager.getTransaction().begin();
// 保存一方(产品)
entityManager.persist(dir);
// 保存多方(产品类型)
entityManager.persist(product2);
entityManager.persist(product);
entityManager.getTransaction().commit();
entityManager.close();
}
保存性能
不管怎么保存(改变persist代码位置),它都会至少执行5条SQL语句完成保存功能。
而完成同样的功能,我们使用单向多对一可以优化为3条。 因此,我们一般不使用单向一对多
原因就是现在外键是由一方来处理,一方处理必须发出额外的update语句
获取代码
@Test
public void get() throws Exception {
EntityManager entityManager = JPAUtils.getEntityManager();
// 拿到一方(产品类别)的数据
ProductDir dir = entityManager.find(ProductDir.class, 1L);
// 打印产品类别
System.out.println(dir);
// 打印产品类别
System.out.println(dir.getProducts());
// 判断该产品类别中是否有产品
if (dir.getProducts().size() == 0) {
System.out.println("当前产品没有类型");
} else {
System.out.println("当前产品有类型");
}
entityManager.close();
}
注意事项
1.配置集合的时候必须配置接口
2.一般都是使用Set接口,只有组合关系使用List接口
3.使用List接口的时候可以配置@Order进行排序
4.实体类不能使用Final修饰(不能继承)
2.双向多对一/双向一对多
配置
配置:尽量让多方来维护的关系,一方放弃管理mappedBy
@OneToMany(mappedBy = "dir")
private List<Product> products = new ArrayList<>();
@Entity
public class ProductDir {
@Id
@GeneratedValue
private Long id;
private String name;
// mappedBy = "dir"表示一方的关系参照多方Prodcut属性dir来管理
@OneToMany( mappedBy = "dir")
// 建议实例化,用的时候不需要在实例化,这里和单向多对一要求不同
private Set<Product2> products = new HashSet<Product2>();
@Entity
public class Product {
@Id
@GeneratedValue
private Long id;
private String name;
// 多Product对一ProductDir
// 多个产品属于一个产品类型
// 外键在那个表,这个表就是多
@ManyToOne(fetch = FetchType.LAZY) // 实现延迟加载
// JoinColum设置了外键的名字,不配置默认一方属性名_id
@JoinColumn(name = "dir_id")
// 这里进行了实例(这种写法是错误的,我们一定不能在这里进行实例化)
private ProductDir dir;
保存
// 一方
ProductDir dir = new ProductDir();
dir.setName("类型1");
// 多方
Product product = new Product();
product.setName("产品1");
Product product2 = new Product();
product2.setName("产品2");
// 只能由一方建立到多方的关系(设置外键)
dir.getProducts().add(product);
dir.getProducts().add(product2);
EntityManager entityManager = JPAUtils.getEntityManager();
entityManager.getTransaction().begin();
entityManager.persist(dir);
entityManager.persist(product);
entityManager.persist(product2);
entityManager.getTransaction().commit();
entityManager.close();
System.out.println("-------------------");
级联操作(掌握)
级联:就是我操作一方数据,就同时可以多方的数据也一并操作级联分为:
级联保存
:@OneToMany(cascade = CascadeType.PRESIST)
级联删除(谨慎使用):
@OneToMany(cascade = CascadeType.REMOVE)
孤儿删除(掌握)
让一方解除关系 ,才能从1方删除多方
@OneToMany(cascade=CascadeType.REMOVE,mappedBy = "dir",orphanRemoval =true)
2.4 强级联 --后面项目里使用 组合关系(单据)
@OneToMany(cascade = CascadeType.ALL,mappedBy = "dir",orphanRemoval = true)
3.单向多对多
配置
User
@Entity
@Table(name="t_user")
public class User {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name="t_user_role",
joinColumns={@JoinColumn(name="user_id")},
inverseJoinColumns ={@JoinColumn(name="role_id")} )
private Set<Role> roles = new HashSet<>();
}
Role
@Entity
@Table(name="t_role")
public class Role {
@Id
@GeneratedValue
private Long id;
private String name;
}
单向对多对保存数据
//3个用户 2个角色
User user1 = new User();
user1.setName("哈哈");
User user2 = new User();
user2.setName("xixi");
User user3 = new User();
user3.setName("啦啦");
Role role1 = new Role();
role1.setName("演员");
Role role2 = new Role();
role2.setName("导演");
//设置关系
user1.getRoles().add(role1);
user2.getRoles().add(role1);
user3.getRoles().add(role1);
user1.getRoles().add(role2);
user2.getRoles().add(role2);
//保存数据
EntityManager entityManager = JpaUtils.getEntityManager();
entityManager.getTransaction().begin();
entityManager.persist(user1);
entityManager.persist(user2);
entityManager.persist(user3);
entityManager.persist(role1);
entityManager.persist(role2);
entityManager.getTransaction().commit();
4.双向多对多
配置
配置
role方
@ManyToMany(fetch = FetchType.LAZY,cascade = CascadeType.REMOVE)
@JoinTable(name="t_user_role",
joinColumns={@JoinColumn(name="role_id")},
inverseJoinColumns ={@JoinColumn(name="user_id")} )
private Set<User> users = new HashSet<>();
user方
@ManyToMany(fetch = FetchType.LAZY,cascade = CascadeType.REMOVE)
@JoinTable(name="t_user_role",
joinColumns={@JoinColumn(name="user_id")},
inverseJoinColumns ={@JoinColumn(name="role_id")} )
private Set<Role> roles = new HashSet<>();
User映射配置
@ManyToMany(cascade = CascadeType.PERSIST)
public void persist2() throws Exception {
// 保存2个用户,保存3个角色(5条)
User user1 = new User("user1");
User user2 = new User("user2");
Role role1 = new Role("role1");
Role role2 = new Role("role2");
Role role3 = new Role("role3");
// 保存中间表:建立用户到角色关系user1(role1,role2),user2(role1,role2,role3)(5条)
user1.getRoles().add(role1);
user1.getRoles().add(role2);
user2.getRoles().add(role1);
user2.getRoles().add(role2);
user2.getRoles().add(role3);
EntityManager entityManager = JPAUtils.getEntityManager();
entityManager.getTransaction().begin();
// 保存用户的同时,级联保存角色
entityManager.persist(user1);
entityManager.persist(user2);
entityManager.getTransaction().commit();
entityManager.close();
System.out.println("------------------------");
}
一对一
一对一 可以看成 一对多 或者 多对一的特殊情况
重点配置:
(1)建议使用单向 多 对一 不要使用单向一对多
(2)如果要使用1对多,尽量使用双向配置,让1方放弃管理
(3) 多对多 如果想相互获取数据 配置双向,如果单向操作 就配置单向
(4)使用多对一来代替一对一,如果实在使用一对一 使用唯一外键的方式