查看“Hibernate笔记 5:实体关联关系”的源代码
←
Hibernate笔记 5:实体关联关系
跳到导航
跳到搜索
因为以下原因,您没有权限编辑本页:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
[[category:Hibernate]] == 关于 == 数据库中多表之间存在着三种关联关系(一对一、一对多、多对多),用于描述实体数据之间的关系,而这种关系也可以通过对象进行描述。 实体关系 # 一对一: #: <syntaxhighlight lang="Java" highlight=""> class A{ B b; } class B{ A a; } </syntaxhighlight> #* 开发中并不常用; # '''一对多''': #: <syntaxhighlight lang="Java" highlight=""> class A{ Set<B> bs; } class B{ A a; } </syntaxhighlight> # '''多对多''': #: <syntaxhighlight lang="Java" highlight=""> class A{ Set<B> bs; } class B{ Set<A> as; } </syntaxhighlight> == 一对多 == 有三种方式维护“一对多”的关联关系: 1、单向关联:一对多 ——仅由“一端”维护关联关系。 2、单向关联:多对一 ——仅由“多端”维护关联关系。 3、双向关联:一对多 ——在“一端”与“多端”均维护关联关系。 '''根据不同的情况和业务需求来选择不同的关联方式。''' 以“客户”(Customer)与“联系人”(LinkMan)为例: # 一个客户可以有多个联系人; # 一个联系人只能被指定给一个客户; === 单向关联:一对多 === 由“'''一端'''”维护关联关系,“多端”仅维护自身属性。 示例: * 在“Customer”中使用“linkMans”来维护其关联的“LinkMan”集合; # Customer: #: <syntaxhighlight lang="Java" highlight="8-9"> public class Customer { private Long cust_id; private String cust_name; private String cust_industry; private String cust_level; private String cust_phone; // 客户类中维护联系人对象集合 private Set<LinkMan> linkMans = new HashSet<LinkMan>(); // getter、setter ... } </syntaxhighlight> #: <syntaxhighlight lang="xml" highlight="13-17"> ... <hibernate-mapping> <class name="cn.itcast.hibernate.domain.Customer" table="cst_customer"> <id name= "cust_id"> <generator class="native"/> </id> <property name="cust_name" length="32"/> <property name="cust_industry" column= "cust_industry"/> <property name="cust_level" column= "cust_level"/> <property name="cust_phone" column= "cust_phone"/> <!-- 配置关联对象集合 --> <set name="linkMans"> <key column="lkm_cust_id"></key> <one-to-many class= "cn.itcast.hibernate.domain.LinkMan"/> </set> </class> </hibernate-mapping> </syntaxhighlight> #* 注意:“lkm_cust_id”为“cst_linkMan”表的外键(参照于“cst_customer”表)。 # LinkMan: #: <syntaxhighlight lang="Java" highlight=""> public class LinkMan { private Long lkm_id; private String 1km_name; private String lkm_phone; // getter、setter ... } </syntaxhighlight> #: <syntaxhighlight lang="xml" highlight=""> ... <hibernate-mapping> <class name="cn.itcast.hibernate.domain.LinkMan" table="cst_linkMan"> <id name= "lkm_id"> <generator class="native"/> </id> <property name="1km_name" length="32"/> <property name="1km_name" column= "1km_name"/> <property name="lkm_phone" column= "lkm_phone"/> </class> </hibernate-mapping> </syntaxhighlight> === 单向关联:多对一 === “一端”仅维护自身属性,由“'''多端'''”维护关联关系。 示例: * 在“LinkMan”中使用“customer”属性来维护其关联的“Customer”; # Customer: #: <syntaxhighlight lang="Java" highlight=""> public class Customer { private Long cust_id; private String cust_name; private String cust_industry; private String cust_level; private String cust_phone; // getter、setter ... } </syntaxhighlight> #: <syntaxhighlight lang="xml" highlight=""> ... <hibernate-mapping> <class name="cn.itcast.hibernate.domain.Customer" table="cst_customer"> <id name= "cust_id"> <generator class="native"/> </id> <property name="cust_name" length="32"/> <property name="cust_industry" column= "cust_industry"/> <property name="cust_level" column= "cust_level"/> <property name="cust_phone" column= "cust_phone"/> </class> </hibernate-mapping> </syntaxhighlight> # LinkMan: #: <syntaxhighlight lang="Java" highlight="6-7"> public class LinkMan { private Long lkm_id; private String 1km_name; private String lkm_phone; // 联系人类中维护客户对象 private Customer customer; // getter、setter ... } </syntaxhighlight> #: <syntaxhighlight lang="xml" highlight="12-13"> ... <hibernate-mapping> <class name="cn.itcast.hibernate.domain.LinkMan" table="cst_linkMan"> <id name= "lkm_id"> <generator class="native"/> </id> <property name="1km_name" length="32"/> <property name="1km_name" column= "1km_name"/> <property name="lkm_phone" column= "lkm_phone"/> <!-- 配置关联对象 --> <many-to-one name="customer" class="cn.itcast.hibernate.domain.Customer" column="lkm_cust_id"/> </class> </hibernate-mapping> </syntaxhighlight> #* 注意:“lkm_cust_id”为“cst_linkMan”表的外键(参照于“cst_customer”表)。 === 双向关联:一对多/多对一 === 在“'''一端'''”与“'''多端'''”均维护关联关系。 示例: * 在“Customer”中使用“linkMans”来维护其关联的“LinkMan”集合; * 在“LinkMan”中使用“customer”属性来维护其关联的“Customer”; # Customer: #: <syntaxhighlight lang="Java" highlight="8-9"> public class Customer { private Long cust_id; private String cust_name; private String cust_industry; private String cust_level; private String cust_phone; // 客户类中维护联系人对象集合 private Set<LinkMan> linkMans = new HashSet<LinkMan>(); // getter、setter ... } </syntaxhighlight> #: <syntaxhighlight lang="xml" highlight="13-17"> ... <hibernate-mapping> <class name="cn.itcast.hibernate.domain.Customer" table="cst_customer"> <id name= "cust_id"> <generator class="native"/> </id> <property name="cust_name" length="32"/> <property name="cust_industry" column= "cust_industry"/> <property name="cust_level" column= "cust_level"/> <property name="cust_phone" column= "cust_phone"/> <!-- 配置关联对象集合 --> <set name="linkMans"> <key column="lkm_cust_id"></key> <one-to-many class= "cn.itcast.hibernate.domain.LinkMan"/> </set> </class> </hibernate-mapping> </syntaxhighlight> # LinkMan: #: <syntaxhighlight lang="Java" highlight="6-7"> public class LinkMan { private Long lkm_id; private String 1km_name; private String lkm_phone; // 联系人类中维护客户对象 private Customer customer; // getter、setter ... } </syntaxhighlight> #: <syntaxhighlight lang="xml" highlight="12-13"> ... <hibernate-mapping> <class name="cn.itcast.hibernate.domain.LinkMan" table="cst_linkMan"> <id name= "lkm_id"> <generator class="native"/> </id> <property name="1km_name" length="32"/> <property name="1km_name" column= "1km_name"/> <property name="lkm_phone" column= "lkm_phone"/> <!-- 配置关联对象 --> <many-to-one name="customer" class="cn.itcast.hibernate.domain.Customer" column="lkm_cust_id"/> </class> </hibernate-mapping> </syntaxhighlight> * 注意:“lkm_cust_id”为“cst_linkMan”表的外键(参照于“cst_customer”表)。 == 多对多 == == cascade(级联操作) == “级联操作”:是指当“'''主控方'''”执行“保存”、“更新”或者“删除”操作时,其关联对象(“被控方”)也执行相同的操作。 1、在映射文件中通过对 cascade 属性的设置来控制是否对关联对象采用级联操作。 2、级联操作对各种关联关系都是有效的。 以下,以“一对多”关系为例。 '''级联是有方向性的''':通过“一端级联操作多端”或“多端级联操作一端”来进行级联操作,二者的含义是完全不同的。 === 级联更新 === ==== 主控端:“一端” ==== 主控端为“一端”,即“'''单向关联:一对多'''”。 Customer: <syntaxhighlight lang="xml" highlight="3"> ... <!-- 配置关联对象集合 --> <set name="linkMans" cascade=""save-update> <key column="lkm_cust_id"></key> <one-to-many class= "cn.itcast.hibernate.domain.LinkMan"/> </set> ... </syntaxhighlight> 测试代码: : <syntaxhighlight lang="Java" highlight="18-23"> @Test // 保存客户,并级联保存其联系人 public void demo1() { Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransaction(); // 创建客户 Customer customer = new Customer(); customer.setCust_name("中国移动"); // 创建联系人 LinkMan linkManl = new LinkMan(); linkManl.setLkm_name("老张"); LinkMan linkMan2 = new LinkMan(); linkMan2.setLkm_name("老李"); // 建立关联关系 customer.getLinkMans().add(linkManl); customer.getLinkMans().add(linkMan2); // 保存 session.save(customer); tx.commit(); } </syntaxhighlight> ==== 主控端:“多端” ==== 主控端为“多端”,即“'''单向关联:多对一'''”。 LinkMan: <syntaxhighlight lang="xml" highlight="3"> ... <!-- 配置关联对象 --> <many-to-one name="customer" cascade=""save-update class="cn.itcast.hibernate.domain.Customer" column="lkm_cust_id"/> ... </syntaxhighlight> 测试代码: : <syntaxhighlight lang="Java" highlight="18-24"> @Test // 保存联系人,并级联保存其客户 public void demo2() { Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransaction(); // 创建客户 Customer customer = new Customer(); customer.setCust_name("中国移动"); // 创建联系人 LinkMan linkManl = new LinkMan(); linkManl.setLkm_name("老张"); LinkMan linkMan2 = new LinkMan(); linkMan2.setLkm_name("老李"); // 建立关联关系 linkManl.setCustomer(customer); linkMan2.setCustomer(customer); // 保存 session.save(linkManl); session.save(linkManl); tx.commit(); } </syntaxhighlight> === 级联删除 === ==== 主控端:“一端” ==== ==== 主控端:“多端” ==== === 级联操作与 SQL === == inverse(关系维护) == == FAQ == === 不配置 cascade 是否可以进行“更新”? === 不配置 cascade 则不可以级联更新。否则,可能出现“瞬时对象异常”(org.hibemate.TransientObjectException)。 示例: 可以通过“'''双向关联'''”的方式完成更新,但是:代码更多,执行的 SQL 也更多。 示例:(非级联更新,必须为:“双向关联:一对多/多对一”) : <syntaxhighlight lang="Java" highlight=""> @Test // 非级联保存:一个客户,及其两个联系人 public void demo() { Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransaction(); // 创建客户 Customer customer = new Customer(); customer.setCust_name("中国移动"); // 创建联系人 LinkMan linkManl = new LinkMan(); linkManl.setLkm_name("老张"); LinkMan linkMan2 = new LinkMan(); linkMan2.setLkm_name("老李"); // 建立关联关系 customer.getLinkMans().add(linkManl); customer.getLinkMans().add(linkMan2); linkManl.setCustomer(customer); linkMan2.setCustomer(customer); // 保存 session.save(customer); session.save(linkManl); session.save(linkManl); tx.commit(); } </syntaxhighlight> 如上代码: # 建立关联时:Customer 对象关联了 LinkMan 对象,同时 LinkMan 对象也关联了 Customer 对象; # 保存对象时:对 Customer 对象进行了保存,也分别对 LinkMan 对象进行了保存; #* 从控制台打印出的 SQL 语句可以看出: #*# 执行了三次 insert(对 customer、linkManl、linkMan2) #*# 执行了两次 update(对 linkManl、linkMan2 更新外键) #*: <syntaxhighlight lang="Java" highlight=""> Hibernate: insert into cst_customer (cust_name, cust_industry, cust_level, cust_phone) values (?, ?, ?, ?) Hibernate: insert into cst_linkMan (1km_name, lkm_phone, lkm_cust_id) values (?, ?, ?, ?) Hibernate: insert into cst_linkMan (1km_name, lkm_phone, lkm_cust_id) values (?, ?, ?, ?) Hibernate: update cst_linkMan set lkm_cust_id where lkm_id=? Hibernate: update cst_linkMan set lkm_cust_id where lkm_id=? </syntaxhighlight> === 不配置 cascade 是否可以进行“删除”? ===
返回至“
Hibernate笔记 5:实体关联关系
”。
导航菜单
个人工具
登录
命名空间
页面
讨论
大陆简体
已展开
已折叠
查看
阅读
查看源代码
查看历史
更多
已展开
已折叠
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
笔记
服务器
数据库
后端
前端
工具
《To do list》
日常
阅读
电影
摄影
其他
Software
Windows
WIKIOE
所有分类
所有页面
侧边栏
站点日志
工具
链入页面
相关更改
特殊页面
页面信息