最近进度有些赶不上了。周末的时候,人开始有些劳累。按部就班的来吧,不能太急于求成了。
老规矩,课堂提纲+没了贴图的笔记。
其实里面的每一行字实际上都配上一副视频截图,但是因为博客不方便上传图片所以在这里看不到。
关联关系中的CRUD_Cascade_Fetch
1 hibernate_1700_one2many_many2one_bi_crud
2 设定cascade以设定在持久化时对于关联对象的操作(CUD,R归Fetch管)
3 cascade仅仅是帮我们省了编程的麻烦而已,不要把它的作用看的太大
a) Cascade的属性是数组格式,指明做什么操作的时候关联对象是绑在一起的
b) refresh= A里面需要读B改过之后的数据
cascade={CascadeType.ALL}
CascadeType取值
ALL Cascade all operations所有情况
MERGE Cascade merge operation合并(merge=save+update)
PERSIST Cascade persist operation存储persist()
REFRESH Cascade refresh operation刷新
REMOVE Cascade remove operation删除
4 铁律:双向关系在程序中要设定双向关联
a) 铁律:双向不要两边设置Eager(会有多余的査询语句发出)
b) 对多方设置fetch的时候要谨慎,结合具体应用,一般用Lazy不用eager,特殊情况(多方数量不多的时候可以考虑,提高效率的时候可以考虑)
@OneToMany(mappedBy="group",
cascade={CascadeType.ALL}, //控制增删改(即CUD)
fetch=FetchType.EAGER //控制查询(即R) EAGER值代表取出关联 LAZY值为不取关联
//多的一方fetch取值默认为LAZY 一的一方默认为EAGER
)
另外:如果User类(即多的一方)中设置fetch=FetchType.LAZY 则在调用多(即Group)的对象值的时候
类似延迟加载 即需要在commit();之前 session还存在时调用 如:
System.out.println(user.getGroup().getName());
session.getTransaction().commit();
7 Update时@ManyToOne()中的cascade参数关系
session.beginTransaction();
User user = (User)session.load(User.class,1);
//user对象属性改变 事务commit时自动判断与数据库原有数据不同可自动update
//此时的update与@ManyToOne()中的cascade或fetch参数取值无关
user.setName("user1");
user.getGroup().setName("group1");
session.getTransaction().commit();
如果user改变在commit()之后 且想要执行Update方法时 user与group表同时更新则,则User类的cascade={CascadeType.ALL},并在程序中写如下代码:
session.beginTransaction();
User user = (User)session.get(User.class,1);
session.getTransaction().commit();
user.setName("user1");
user.getGroup().setName("group1");
Session session2 = sessionFactory.getCurrentSession();
session2.beginTransaction();
session2.update(user);
session2.getTransaction().commit();
8 Delete时@ManyToOne()中的cascade关系
如果User及Group类中均设为@ManyToOne(cascade={CascadeType.All}),那么在执行如下:
session.beginTransaction();
User user = (User)session.load(User.class,1);
session.delete(user);
session.getTransaction().commit();
注意:此处删除的是 多对一(即User对Group) 中的“多”的一方(User类)
会删除user及user对应的group,再反向对应group的user都会删除,原因就是设置了@ManyToOne(cascade={CascadeType.All})
三种方法可避免全部删除的情况:
1. 去掉@ManyToOne(cascade={CascadeType.All})设置;
2. 直接写Hql语句执行删除;
3. 将user对象的group属性设为null,相当于打断User与Group间的关联,代码如下
session.beginTransaction();
User user =(User)session.load(User.class,1);
user.setGroup(null);
session.delete(user);
session.getTransaction().commit();
注意:如果删除的是 多对一中的“一”的一方(Group类)时,如果使用第3种方式(user属性设为null)来打断两个对象间的关联的话,代码与之前不同,如下:
session.beginTransaction();
Group group = (Group)session.load(Group.class,1);
//循环将group中的set集合下的各个user对象设为null
//相当于先将数据库中user表中与group表关联的字段(即groupid)设为null
for(User user:group.getUsers()){
System.out.println(user.getName());
user.setGroup(null);
}
//再将group的set集合设为null,相当于将group表中与user表关联的字段(即userid)设为null
//此句的前提是user表中的关联字段(groupid)已经为null,如没有则相当于破坏了一对多关联,会报错
group.setUsers(null);
session.delete(group);
session.getTransaction().commit();
9 O/RMapping 编程模型
a) 映射模型
i. jpa annotation(java提供的annotation配置--常用)
ii. hibernateannotation extension(Hibernate扩展的annotation配置--较少用)
iii. hibernatexml(Hibernate的xml配置方式--常用)
iv. jpaxml(java提供的xml配置--较少用)
b) 编程接口
i. Jpa(不常用)
ii. hibernate(现在用)
c) 数据査询语言
i. HQL
ii. EJBQL(JPQL)
11 如果想消除关联关系,先设定关系为null.再删除对应记录,如果不删记录,该记录变成垃圾数据
12 练习:多对多的CRUD
teacher | student |
t1 | s1 |
t1 | s2 |
t2 | s1 |
t2 | s2 |
关系映射总结
2 CRUD,按照自然的理解即可(动手测试)
集合映射(不太重要)
1 项目名称:hibernate_1800_Collections_Mapping
3 List (与Set差不多多个@OrderBy)
a)@OrderBy
继承映射(不太重要)
a) 一张总表SINGLE_TABLE
i. hibernate_1900_lnheritence_Mapping_Single_Table
b) 每个类分别一张表TABLE_PER_CLASS
i.hibernate_2000_lnheritence_Mapping_Table_Per_Class
c) 每个子类一张表jOINED
i. hibernate_2100_lnheritence_Mapping_JOINED
父类上加注解@Inheritance(strategy=InheritanceType.JOINED)
@Inheritance(strategy=InheritanceType.JOINED)
public class Person {... ...}
作业:
1 学生课程、分数的设计(重要)
a) 使用联合主键@Embeddedld
i.实现Serializable接口
b) 不使用联合主键(视频中实际例子采用此类方法)
注:自己的项目与马老的方式不同,但可实现同样的功能(除从学生查课程外),具体见项目hibernate_2300_Stu_Course_Score
a) 实体类(表)
b) 导航(编程方便)
c) 确定了编程方式
3 树状结构的设计(至关重要)
a) 在同—个类中使用One2Many和Many20ne
关系模型(Tree)
Tree(int id,String name,Tree parent,List children)多
privateList<Tree> children = new ArrayList<Tree>();
@Id
@GeneratedValue
public int getId(){
return id;
}
@ManyToOne
@JoinColumn(name="parent_id")
public Tree getParent(){
return parent;
}
//fetch=FetchType.EAGER可省略 即为@OneToMany的默认值fetch=FetchType.LAZY
//若树形较小 可使用EAGER 一次全部载入内存
//若为LAZY则查询树形时不会一次全部载入内存(适用于较大的树形),会每取一个叶子节点就select
一次
@OneToMany(mappedBy="parent",
cascade={CascadeType.ALL},
fetch=FetchType.EAGER )
public List<Tree> getChildren() {
return children;
}
046 双向多对多(很少用)
在student这边加teacher的set再写@many-to-many注解就可以了
Xml的写法 在student这边添加这个
047 关联关系的CRUD
只要有关联就要考虑连带关系读一个的时候要不要读另一个呢? 删除一个的时候要不要删除另一个呢?更新一个的时候会不会更新另一个呢?
这些是要动手试 + 把握规律
一对多多对一 双向
测试的时候 before和after的写法
要存到数据表里要在程序里先写好这两个对象的关系必须要有这个group, user才能设定group的id 为这个group
级联属性 casecade 有这几种级联关系
All 对其中一个对象的任何持久化操作(常用) 都会关联另一个关系 拿出一个 另一个也会拿出
Refresh 刷新(少用)
Persistent 存储级联
Merge 合并 合并的时候会级联
Remove 删除级联
把user的group级联设为all
这段程序可以执行并且会帮你把你定义的group存进去
加入多层级联每层都设all就可以了
关联关系搞不清楚的时候就不用级联了 完全可以用编程实现替代
048
为group里面的users添加成员的时候要用g.getUsers().add()
加入在group里面设定users的casecadeType 为All 则可以帮你存储u1 u2
但是这样会导致group_id 为空
要手动设置users的group属性
1 凡是双向的关联 都要手动设置数据库关联的外键值
2 双向一定要设定mappedBy
两个铁律
048 查看读取数据的情况
先用testSaveGroup存一点数据进去再取来看一下 user和group的级联关系
048 fetch管读取的关联(lazy不关联读 eager关联读)
Cascade管 插删改
这种情况可以取出group中的users
049 多对一种 fetch是eager 因为只用取一个简单属性 而不是一个集合
049 有时多对一的双向 双方fetch不能都设eager 要不然一方取的时候 对方又要回取这方
浪费了一次一模一样的sql语句
049
Xml设置
Inverse的意思是关联关系在对方起作用
一般情况下 多对一 lazy 一对多 eager 前提是 多得那方 不是很多
Id pid 树
050 cascade 更新
Cascade 的这几种类型分别是指调用这几种方法的时候会级联
051 做删除的时候 一般先load一下 确定有这个对象 再删
051 当user级联group的时候(ALL型) 删user也会把关联的group删掉了 然后删group又会先把group底下的所有user也删掉
051 级联关系不能满足关联关系的时候
方法1: 打破关联再删
方法二: 自己写语句
052
删除一这方时会级联删除它下面的关联的集合所以要先把它底下的users一个一个都拿出来并且设user的group为空
Ejbql是HQL的子集
Fetch_ 影响load和get 以及一些查询语句
Cascade 影响修改数据的语句和方法
053 一般情况下 集合用set 当取出来的数据需要排序的时候 可以用list
默认排序主键
可以自定义排序根据哪个字段用升序还是降序
用map的情况: key不能重复一般用主键 在底下的@Mapkey里面设置字段
查看map里面的内容的遍历写法
054
面向对象的树状结构父亲是一个对象 孩子是一个集合
055
继承在数据库里设计的时候的表现
1) (用得不多)(single table)用一张表把不同子类的对象全部装在里面 同时存不同的类型的子类 并且有一个字段专门标记区分是哪个子类(不足: 子类差异大的时候冗余列多)
父类 选择的区分字段类型是String
子类
可以父类引用装子类对象
2) (table per class)每个类一张表(不足: 映射到对象的时候 并不能实现Personperson = person(load(2)) )因为多个表id肯定会互相重复
oracle生成id可以使这些表用同一个sequence(容易实现)
在其他地方可以用table方式设置
在子类里面只用设@entity id在父类里面设好了
3) (用得比较多)(joined)一个表存公有属性 每个子类表里面存储自己特定的内容
第三种只用一句话
子类里面只用@entity就可以了
*读出来的时候 都尽量不要用父类引用装子类对象
各子表的id参考公共属性表的id
(缺点: 要做连接当有一个新的子类时要建一张新表)
056 树状结构
表设计
每个记录的pid要参考本表的id
其他设置都和普通表一样 id也自动生成