单向多对一
1) 保存
public void testManyToOnePersistence() {//多对一映射关联关系//一个customer可以有多个order。Customer customer = new Customer();customer.setAge(112);customer.setLastName("b");customer.setEmail("b");customer.setBirth(new Date());customer.setCreateTime(new Date());Order order = new Order();order.setOderName("o-ff-1");Order order1 = new Order();order1.setOderName("o-ff-2");order.setCustomer(customer);order1.setCustomer(customer);entityManager.persist(customer);entityManager.persist(order);entityManager.persist(order1);}
注意: 保存多对一时,建议先保存1的一端,后保存n的一端,这样不会多出额外的update语句
2) 查询
public void testManyToOneFind() {Order order = entityManager.find(Order.class, 1);System.out.println(order.getOrderName());System.out.println(order.getCustomer().getLastName());}
默认情况下,使用左外连接的方式来获取n的一端的对象和其关联的1的一端的对象
可以在Order.getCustomer()使用ManyToOne(fetch = FetchType.LAZY) 来修改关联属性的加载策略 
3) 删除
public void testManyToOneRemove() {// 删除多的一方Order order = entityManager.find(Order.class, 1);entityManager.remove(order);// 删除1的一方Customer customer = entityManager.find(Customer.class, 7);entityManager.remove(customer);}
注意: 不能直接删除1的一端,因为有外键;除非多的一端没有数据,否则会报错
单向一对多
1) 保存
@Testpublic void testOneToManyPersistence() {Customer customer = new Customer();customer.setAge(16);customer.setEmail("qqqq@qq.com");customer.setLastName("yy");customer.setBirth(new Date());customer.setCreatedTime(new Date());Order order1 = new Order();order1.setOrderName("o-y-1");Order order2 = new Order();order2.setOrderName("o-y-2");// 设置关联关系customer.getOrders().add(order1);customer.getOrders().add(order2);// 执行保存操作entityManager.persist(customer);entityManager.persist(order1);entityManager.persist(order2);}
注意: 单向1-n 执行保存时,一定会多出update语句,因为n的一端在插入时不会同时插入外键列
2) 查询
public void testOneToManyFind() {Customer customer = entityManager.find(Customer.class, 9);System.out.println(customer.getLastName());System.out.println(customer.getOrders().size());}
默认懒加载,在Customer.getOrders()中使用OneToMany(fetch = FetchType.EAGER) 修改加载策略
3)删除
public void testOneToManyRemove() {Customer customer = entityManager.find(Customer.class, 10);entityManager.remove(customer);}
默认情况下,若删除1的一端,则会把关联的n的一端的外键置空,然后进行删除1的一端
使用OneToMany(cascade = CascadeType.REMOVE) 修改删除策略
双向一对多
双向一对多关系中,必须存在一个关系维护端,在 JPA 规范中,要求 many 的一方作为关系的维护端(owner side), one 的一方作为被维护端(inverse side)。
可以在 one 方指定 OneToMany 注释并设置 mappedBy 属性,以指定它是这一关联中的被维护端,many 为维护端。
在 many 方指定 ManyToOne 注释,并使用 JoinColumn 指定外键名称 

public void testDoubleOneToManyPersistence() {Customer customer = new Customer();customer.setAge(16);customer.setEmail("ggg@qq.com");customer.setLastName("bb");customer.setBirth(new Date());customer.setCreatedTime(new Date());Order order1 = new Order();order1.setOrderName("o-b-1");Order order2 = new Order();order2.setOrderName("o-b-2");// 设置关联关系customer.getOrders().add(order1);customer.getOrders().add(order2);order1.setCustomer(customer);order2.setCustomer(customer);// 执行保存操作entityManager.persist(customer);entityManager.persist(order1);entityManager.persist(order2);}
若是双向1-n的关联关系,执行保存时
先保存n的一端,再保存1的一端,默认情况下,会多出4条update语句
先保存1的一端,会多出n条update语句
建议: 使用n的一方来维护关联关系,而1的一方不维护关联关系,这样会有效的减少sql语句
注意: 若在1的一端的@OneToMany中使用mappedBy属性,则@OneToMany端就不能使用@JoinColumn属性了
双向一对一
基于外键的 1-1 关联关系:在双向的一对一关联中,需要在关系被维护端(inverse side)中的 OneToOne 注释中指定 mappedBy,以指定是这一关联中的被维护端。同时需要在关系维护端(owner side)建立外键列指向关系被维护端的主键列。 
1) 保存
public void testOneToOnePersistence() {Manager manager = new Manager();manager.setMgrName("m-22");Department department = new Department();department.setDeptName("d-22");// 设置关联关系manager.setDepartment(department);department.setManager(manager);// 执行保存操作entityManager.persist(department);entityManager.persist(manager);}
双向1-1的关联关系,建议先保存不维护关联关系的一方,即没有外键的一方,这样不会多出update语句

2) 查询
public void testOneToOneFind() {Department department = entityManager.find(Department.class, 1);System.out.println(department.getDeptName());System.out.println(department.getManager().getClass().getName());}
默认情况下,若获取维护关联关系的一方,则会通过左外连接获取其关联的对象
可以通过OneToOne(fetch = FetchType.LAZY)来修改加载策略
public void testOneToOneFind2() {Manager manager = entityManager.find(Manager.class, 1);System.out.println(manager.getMgrName());System.out.println(manager.getDepartment().getClass().getName());}
默认情况下,若获取不维护关联关系的一方,也会通过左外连接获取其关联的对象
可以通过OneToOne(fetch = FetchType.LAZY)来修改加载策略,但依然会再发送SQl语句来初始化器关联的对象
说明在不维护关联关系的一方,不建议修改fatch属性
不延迟加载的原因:
1.如果延迟加载要起作用, 就必须设置一个代理对象.
2.Manager 其实可以不关联一个 Department
3.如果有 Department 关联就设置为代理对象而延迟加载, 如果不存在关联的 Department 就设置 null, 因为外键字段是定义在 Department 表中的,Hibernate 在不读取 Department 表的情况是无法判断是否有关联有 Deparmtment, 因此无法判断设置 null 还是代理对象, 而统一设置为代理对象,也无法满足不关联的情况, 所以无法使用延迟加载,只 有显式读取 Department.
双向多对多
在双向多对多关系中,我们必须指定一个关系维护端(owner side),可以通过 ManyToMany 注释中指定 mappedBy 属性来标识其为关系维护端。
ManyToMany
@JoinTable(name=”中间表名称”,
joinColumns={
@joinColumn(name=”本类的外键”,referencedColumnName=”本类与外键对应的主键”)
},inversejoinColumns={
@JoinColumn(name=”对方类的外键”,referencedColunName=”对方类与外键对应的主键”)
}
)


1) 保存
// 共8条insert语句public void testManyToManyPersistence() {Item i1 = new Item();i1.setItemName("i-1");Item i2 = new Item();i2.setItemName("i-2");Category c1 = new Category();c1.setCategoryName("c-1");Category c2 = new Category();c2.setCategoryName("c-2");// 设置关联关系i1.getCategories().add(c1);i1.getCategories().add(c2);i2.getCategories().add(c1);i2.getCategories().add(c2);c1.getItems().add(i1);c1.getItems().add(i2);c2.getItems().add(i1);c2.getItems().add(i2);// 执行保存entityManager.persist(i1);entityManager.persist(i2);entityManager.persist(c1);entityManager.persist(c2);}
2) 查询
public void testManyToManyFind() {/*Item item = entityManager.find(Item.class, 1);System.out.println(item.getItemName());System.out.println(item.getCategories().size());*/Category category = entityManager.find(Category.class, 1);System.out.println(category.getCategoryName());System.out.println(category.getItems().size());}
对于关联的集合对象,默认使用懒加载的策略
使用维护关联的关系一方获取,还是使用不维护关联关系的一方获取,sql语句相同
