前提:表数据和表数据之间可以存在的关系?
1、一对多(最多)
建表原则:在多的一方创建一个字段当成是外键
2、多对多
建表原则:创建一张中间表,这个中间表中至少需要2个字段,分别指向各自表的主键
3、一对一(企业开发中很少,其实就是合成一张表来使用)
引申到,实体类和实体类之间可以存在的关系?
1、一对多
创建原则:在一中创建多的集合;在多中创建一的的对象。约定:让一放弃外键的维护权
2、多对多
创建原则:互相都有对方的集合。约定:让被动的放弃外键的维护权
3、一对一
创建原则:互相都有对方的对象
一、Hibernate的一对多映射
示例:假设Customer客户与Linkman联系人存在一对多的关系。每个Customer对象可对应多个Linkman对象。
1、创建实体类
2、创建映射文件
创建Customer.hbm.xml和LinkMan.hbm.xml
3、在hibernate.cfg.xml中加载映射关系文件Customer.hbm.xml和LinkMan.hbm.xml的地址
4、利用Hibernate创建表结构
执行获得session的语句,就可创建对应的数据库表结构。
5、代码测试
6、结果显示
7、双向维护产生多余SQL
①产生原因:一级缓存的存在
②解决办法:是因为双方都在维护外键,让其中一方放弃外键的维护即可解决。
约定:让一放弃外键的维护权,在一的配置文件里设定标签 :inverse="true"
③产生原理:如下图:
执行session.save(customer);会根据主键生成策略产生id值同时插入到数据库中,由于维护外键,所以也会保存wj_id字段,但此时这个值不知道(wj_id是最终保存到linkman表的,此时linkman表还未保存)。我们知道插入到数据库中的数据会保存到一级缓存中一份,所以此时缓存中的wj_id值是空。
执行session.save(linkman);会根据主键生成策略产生id值同时插入到数据库中,同样也维护外键,根据linkman表知道wj_id是拿customer表的id值作为自己的值插入数据库中。我们知道插入到数据库中的数据会保存到一级缓存中一份,此时linkman的缓存中的wj_id值是1,也会把customer的缓存的wj_id更新为1。
执行tx.commit();发现customer的存储区的wj_id是1,而快照区是空,所以自动发送update语句,产生冗余SQL。
8、一对多的级联保存
级联:操作一个对象的时候,是否操作其关联对象。
级联操作是有方向性。①保存一的数据,级联保存多的数据,反过来也能实现。约定保存一
②删除一的数据,级联删除多的数据,反过来也能实现。约定删除一
配置:cascade="save-update" 级联保存:保存谁 ,在该类的配置文件上配置级联
"delete" 级联删除:删除谁 ,在该类的配置文件上设置级联
测试保存与删除:
二、Hibernate的多对多映射(代码参考hibernate_day03的TestCustomer2.java)
示例:假设User用户与Role角色存在多对多的关系。
1、创建实体类,互相创建对方的Set集合
2、创建映射文件
创建User.hbm.xml和Role.hbm.xml
被动的一方放弃外键的维护权。如用户和角色,肯定是用户选择角色,所以角色被动。
3、在hibernate.cfg.xml中加载映射关系文件
4、利用Hibernate创建表结构(包括中间表)
5、级联保存操作(基本不用);
级联删除操作(不但基本不用,还要避免去使用),普通删除即满足业务需求
6、常用的级联处理