一、概述
例如,以客户(Customer)和订单(Order)为例,一个客户能有多个订单,一个订单只能有一个客户。 从Customer到Order是一对多关联,在java类中的面向对象设计应该一个Customer对象包含多个Order对象,因此应该定义一个集合,来包含所有的Order对象。 ?从Order到Customer是多对一关联,在java类中设计每个Order对象需要关联一个Customer对象,因此Order类中应该定义一个Cutomer类型的属性,来引用关联的customer对象。但是在关系数据库中,只存在主外键参照关系来表达两者的关联。
二、实例
(1)先创建两个实体类 Customer和Order
?public class Customer { ???????????????????private Integer id; ???????????????????private String name; ???????????????????private Set <Order> orders=new HashSet<Order>(); ???????????????????public Integer getId() { ???????????????????????return id; ???????????????????} ???????????????????public void setId(Integer id) { ???????????????????????this.id = id; ???????????????????} ???????????????????public String getName() { ???????????????????????return name; ???????????????????} ???????????????????public void setName(String name) { ???????????????????????this.name = name; ???????????????????} ???????????????????public Set getOrders() { ???????????????????????return orders; ???????????????????} ???????????????????public void setOrders(Set orders) { ???????????????????????this.orders = orders; ???????????????????} ???????????} ????????????public class Order { ???????????????private Integer id; ???????????????private String name; ???????????????private Customer customer; ???????????????public Integer getId() { ???????????????????return id; ???????????????} ???????????????public void setId(Integer id) { ???????????????????this.id = id; ???????????????} ???????????????public String getName() { ???????????????????return name; ???????????????} ???????????????public void setName(String name) { ???????????????????this.name = name; ???????????????} ???????????????public Customer getCustomer() { ???????????????????return customer; ???????????????} ???????????????public void setCustomer(Customer customer) { ???????????????????this.customer = customer; ???????????????} ???????????}
(2)实体类写好了,使用Hibernate映射文件来映射关系
创建Customer.hbm.xml:
????????????<hibernate-mapping > ???????????????<!--指定实体类和表的映射关系--> ???????????????<class name="com.cad.domain.Customer" table="customer"> ???????????????????<id name="id" column="id"> ???????????????????????<generator class="native"></generator> ???????????????????</id> ???????????????????<property name="name" column="name"></property> ???????????????????<!--使用<set>元素来映射set集合类型--> ???????????????????<!-- ???????????????????????name:持久化类中的属性名 ???????????????????--> ???????????????????<set name="orders"> ???????????????????????<!--<key>元素设定所关联的持久化类对应的表的外键--> ???????????????????????<!--<one-to-many>元素设定关联的持久化类--> ???????????????????????<key column="cid"/> ???????????????????????<one-to-many class="com.cad.domain.Order"/> ????????????????????</set> ???????????????</class> ????????????</hibernate-mapping> ?????????????Hibernate根据映射文件获得以下信息 ???????????-<set>元素表明Customer类中的orders属性为java.util.Set集合 ???????????-<one-to-many>元素表明orders集合中存放的是一组order对象 ???????????-<key>元素表明orders表通过外键cid关联customer表
???????????创建Order.hbm.xml
???????????<hibernate-mapping > ???????????????<class name="com.cad.domain.Order" table="order"> ???????????????????<id name="id" column="id"> ???????????????????????<generator class="native"></generator> ???????????????????</id> ???????????????????<property name="name" column="name"></property> ???????????????????<!--<many-to-one>元素建立了customer属性和对应表中外键的映射--> ???????????????????<!-- ???????????????????????name:持久化类中的属性名 ???????????????????????column:表中的外键 ???????????????????????class:关键的Customer对象实现类 ???????????????????--> ???????????????????<many-to-one name="customer" column="cid" class="com.cad.domain.Customer"></many-to-one> ???????????????</class> ????????????</hibernate-mapping> ?
(3)在hibernate.cfg.xml中配置映射文件
????????????????<mapping resource="com/cad/domain/Customer.hbm.xml"/> ?????????????????<mapping resource="com/cad/domain/Order.hbm.xml"/>
(4)测试
????????????????//添加方法 ?????????????????????@Test ???????????????????public void test() { ???????????????????????//读取配置文件 ???????????????????????Configuration conf=new Configuration().configure(); ???????????????????????//根据配置创建factory ???????????????????????SessionFactory sessionfactory=conf.buildSessionFactory(); ???????????????????????session = sessionfactory.openSession(); ?????????????????????????Transaction ts=session.beginTransaction(); ?????????????????????????//创建Customer ???????????????????????Customer c=new Customer(); ???????????????????????c.setName("张三"); ????????????????????????//创建订单 ???????????????????????Order o1=new Order(); ???????????????????????o1.setName("矿泉水"); ???????????????????????Order o2=new Order(); ???????????????????????o2.setName("方便面"); ????????????????????????//双向关联 ???????????????????????c.getOrders().add(o1); ???????????????????????c.getOrders().add(o2); ???????????????????????o1.setCustomer(c); ???????????????????????o2.setCustomer(c); ???????????????????????//保存 ???????????????????????session.save(c); ???????????????????????session.save(o1); ???????????????????????session.save(o2); ???????????????????????ts.commit(); ???????????????????????session.close(); ???????????????????????sessionfactory.close(); ???????????????????} ???????????????????然后执行,控制台会打印如下语句 ???????????????????????????Hibernate: ????????????????????????????????insert ????????????????????????????????into ???????????????????????????????????customer ???????????????????????????????????(name) ????????????????????????????????values ???????????????????????????????????(?) ???????????????????????????Hibernate: ????????????????????????????????insert ????????????????????????????????into ???????????????????????????????????orders ???????????????????????????????????(name, cid) ????????????????????????????????values ???????????????????????????????????(?, ?) ???????????????????????????Hibernate: ????????????????????????????????insert ????????????????????????????????into ???????????????????????????????????orders ???????????????????????????????????(name, cid) ????????????????????????????????values ???????????????????????????????????(?, ?) ???????????????????????????Hibernate: ????????????????????????????????update ???????????????????????????????????orders ????????????????????????????????set ???????????????????????????????????cid=? ????????????????????????????????where ???????????????????????????????????id=? ???????????????????????????Hibernate: ????????????????????????????????update ???????????????????????????????????orders ????????????????????????????????set ???????????????????????????????????cid=? ????????????????????????????????where ???????????????????????????????????id=? ???
我们来执行删除操作,直接删除Customer,但由于还有Order关联着Customer 会执行成功么?
???????????????????????????@Test ???????????????????????????public void test() { ???????????????????????????????//读取配置文件 ???????????????????????????????Configuration conf=new Configuration().configure(); ???????????????????????????????//根据配置创建factory ???????????????????????????????SessionFactory sessionfactory=conf.buildSessionFactory(); ???????????????????????????????session = sessionfactory.openSession(); ?????????????????????????????????Transaction ts=session.beginTransaction(); ????????????????????????????????Customer c=session.get(Customer.class, 2); ?????????????????????????????????//删除Customer ???????????????????????????????session.delete(c); ???????????????????????????????ts.commit(); ???????????????????????????????session.close(); ???????????????????????????????sessionfactory.close(); ???????????????????????????} ???????????????????????执行,打印如下语句 ???????????????????????????Hibernate: ????????????????????????????????select ???????????????????????????????????customer0_.id as id1_0_0_, ???????????????????????????????????customer0_.name as name2_0_0_ ????????????????????????????????from ???????????????????????????????????customer customer0_ ????????????????????????????????where ???????????????????????????????????customer0_.id=? ???????????????????????????Hibernate: ????????????????????????????????update ???????????????????????????????????orders ????????????????????????????????set ???????????????????????????????????cid=null ????????????????????????????????where ???????????????????????????????????cid=? ???????????????????????????Hibernate: ????????????????????????????????delete ????????????????????????????????from ???????????????????????????????????customer ????????????????????????????????where ???????????????????????????????????id=? ????????我们会发现Hibernate会自动将Order中的cid设置为null,然后执行删除操作 ???????我们发现Hibernate还是挺智能的,但这是由inverse属性操控的。
三、< set >元素的inverse属性
inverse所描述的是对象之间关联关系的维护方式。 inverse属性指定由哪方来维护关联关系。inverse默认为false,即关联关系由自己控制,若为true,则反转,关联关系由对方控制.Inverse属性的作用是:是否将对集合对象的修改反映到数据库中。 在映射一对多的双向关联关系中,应该在"一"方把inverse属性设为true,由对方来维护主键关联关系.所以上述例子中,inverse默认是false.即Customer维护关联关系,所以Customer会执行两条更新语句来更新Order的cid.但是我们Order在插入的时候已经插入cid,所以这样会影响性能,我们只需要将Customer的<set>元素的inverse属性改为true即可。 我们的删除案例中也是,Customer执行删除时,会先去把Order的主键约束解除,然后删除。我们只需要将Customer的inverse设置为true,然后由对方维护关联关系,我们再进行删除时,就会出现异常,因为有主键约束,我们Customer不再维护关联关系。
四、级联操纵
在实际应用中,对象和对象之间是相互关联的。例如我们的一对多关联关系。
在关系-对象映射文件中,用于映射持久化类之间关联关系的元素,如 < set>,< many-to-one>,< one-to-many>,都有一个cascade属性,用来指定如何操纵与当前对象关联的其他对象。
???我们先看下面的例子,我们创建一个Customer,再创建两个Order,然后关联 ???我们只保存Customer,会抛出org.hibernate.TransientObjectException异常,这是为什么呢? ???这是因为我们的Customer的inverse为false,关联关系由Customer维护。我们保存Customer时, ???会维护Customer中orders中的所有Order的主键,但是Order是临时对象,并没有转变为持久状态,这时候就会抛出异常。 ???????????@Test ???????????public void test() { ???????????????//读取配置文件 ???????????????Configuration conf=new Configuration().configure(); ???????????????//根据配置创建factory ???????????????SessionFactory sessionfactory=conf.buildSessionFactory(); ???????????????session = sessionfactory.openSession(); ?????????????????Transaction ts=session.beginTransaction(); ????????????????Customer c=new Customer(); ????????????????c.setName("jack"); ????????????????Order o1=new Order(); ????????????????o1.setName("苹果"); ????????????????Order o2=new Order(); ????????????????o2.setName("香蕉"); ????????????????c.getOrders().add(o1); ????????????????c.getOrders().add(o2); ????????????????o1.setCustomer(c); ????????????????o2.setCustomer(c); ????????????????session.save(c); ???????????????ts.commit(); ???????????????session.close(); ???????????????sessionfactory.close(); ???????????}
当Hibernate持久化一个临时对象时,并不会自动持久化所关联的其他临时对象,所以会抛出异常。
如果我们希望Hibernate持久化对象时自动持久化所关联的其他对象,那么就需要指定cascade属性
(1)级联保存和更新
???当我们持久化对象时自动持久化所关联的其他对象。 ????把cascade属性设置为save-update ,这时候我们再执行上面的代码就会自动帮我们保存Customer关联的Order对象。 ???当cascade属性为save-update时,表明保存或更新当前对象时,会级联保存或更新与它关联的对象。
(2)级联删除
如果我们的cascade属性为delete时,我们删除当前对象,会自动删除与之关联的对象。 ???慎用这个delete属性。 ???例如:我们的Order配置了这个属性,Customer也配置了这个属性,我们删除订单时,因为是级联删除 ???所以会查找Customer,删除Customer,但Customer也配置了级联删除,所以会查找所有关联的订单,最后会删除该客户的所有订单和该客户。
(3)孤儿删除
???如果我们的对象和关联的对象解除关系后,希望自动删除不再关联的对象。 ???需要将cascade设置为delete-orphan. ???例如 ,我们设置cascade="delete-orphan" ????????????????????Transaction ts=session.beginTransaction(); ????????????????????Customer c=session.get(Customer.class, 7); ????????????????????Order order=(Order) c.getOrders().iterator().next(); ????????????????????c.getOrders().remove(order); ????????????????????order.setCustomer(null); ????????????????????ts.commit(); ????我们解除Customer和Order的关系,Hibernate就会自动删除Order。 ?????当cascade的值为all时,是save-update和delete的整合。 ???当cascade的值为all-dalete-orphan时,是all和delete-orphan的整合。
(八)Hibernate的一对多关联关系
原文地址:https://www.cnblogs.com/yuexiaoyun/p/9452363.html