21~56讲
10、多对多(teacher-student)
性能不佳,一般会拆成两个一对多,hibernate会创建中间表做关联。
Teacher(id,name,students) -->private Set<Student> students
Student(id,name,teachers) -->private Set<Teacher> teachers
Teacher.hbm.xml中定义:
<class name="Teacher">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="students" table="teacher_student"> --->中间表
<key column="teacher_id"/>
<many-to-many class="Student" column="student_id"/>
</set>
</class>
Student.hbm.xml中定义(与上类似):
<class name="Student">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="teachers" table="teacher_student"> --->中间表
<key column="student_id"/>
<many-to-many class="Teacher" column="teacher_id"/>
</set>
</class>
插入操作代码:
Student stu1 = new Student();
stu1.setName("stu1");
Student stu2 = new Student();
stu2.setName("stu2");
Set<Student> s = new HashSet<Student>(); //也可以定义HashSet<Teacher> ,让学生知道老师,但两种方式不能并存
s.add(stu1);
s.add(stu2);
Teacher tea1 = new Teacher();
tea1.setName("tea1");
Teacher tea2 = new Teacher();
tea2.setName("tea2");
tea1.setStudents(s);
tea2.setStudents(s); //老师知道学生
11、组件映射(User)
同多对一和一对多,后两者是将复杂属性(非基本类型,如自定义的Name类)分到另外一张表中与User关联,而组件关联则是全部放在当前表中展现,其他无区别
例如User有Name属性,Name类包括firstName和lastName两个属性。
User.hbm.xml中定义:
<!--
<property name="name"/>
-->
<component name="name">
<property name="firstName" column="first_name"/>
<property name="lastName" column="last_name"/>
</component>
则数据库User表中字段有(id,first_name,last_name),而不是(id,name_id)
12、hibernate中的集合类型
1)将一对多中Department的emps的类型改为List
Department(id,name,emps) -->private List<Employee> emps
Department.hbm.xml中定义:
<list name="emps">
<key column="depart_id"/>
<list-index column="order_co"/> ---->供hibernate记下每个记录的添加顺序,该列存在Employee表中
<one-to-many class="Employee"/>
</list>
想在代码中用List类型,但是又不想hibernate因为list排序而耗性能,可以使用bag标签(与list一样,但是无需保证顺序)
<bag name="emps">
<key column="depart_id"/>
<one-to-many class="Employee"/>
</bag>
2)将一对多中Department的emps的类型改为Map
Department(id,name,emps) -->private Map<String,Employee> emps
Department.hbm.xml中定义:
<map name="emps">
<key column="depart_id"/>
<map-key type="string" column="name"/>
<one-to-many class="Employee"/>
</map>
13、关联关系的级联操作
默认hibernate是不进行级联操作的,例如保存Department时,不会自动保存Employee对象。
可以在Department.hbm.xml中修改一下
<set name="emps" cascade="save-update">
则代码中仅需save(depart),而无需save(employee)
常用cascade有:none(默认)、all、save-update、delete....标签中多个时逗号分割
一般对many-to-one,many-to-many不设置级联,在one-to-one,one-to-many中设置级联
14、懒加载(提高性能,将和数据库交互的时间延后)
1)load
User user = s.load(User.class,id);
Hibernate.initialize(user); ---->强迫此处load方法生成的代理user初始化一下(类似在当前的session范围中访问一下数据库),则后续在离开这个session范围后,使用user代理不会报错。
2)one-to-one懒加载
必须同时满足如下三个条件才能实现懒加载(只对从表有效,如IDCard,查询get(IDCard.class,id)时,不会查询Person)
lazy!=false --默认
constrained=true(主表不能设置如此)
fetch=select --默认
3)one-to-many懒加载
必须同时满足如下两个条件才能实现懒加载
lazy!=false --默认
fetch=select --默认
4)many-to-one懒加载
必须同时满足如下两个条件才能实现懒加载
lazy!=false --默认
fetch=select --默认
5)many-to-many懒加载
必须同时满足如下两个条件才能实现懒加载
lazy!=false --默认
fetch=select --默认
15、缓存
1)一级缓存(Session)
save,update,saveOrUpdate,load.get,list,iterate,lock这些方法都会将对象放在一级缓存中。
一级缓存不能控制缓存的数量,所以要注意内存溢出,可通过evict,clear方法清除缓存中的内容。
get和load方法会先去缓存中找。
2)二级缓存(SessionFactory)
hibernate.cfg.xml中配置
cache.use_second_level_cache:true 默认,可不配
cache.provider_class: org.hibernate.cache.OSCacheProvider (增加相应lib包)
指定要缓存的类
<class-cache class="org.hibernate.test.User" usage="read-only"/> usage:read-only,read-writer....
或在User.hbm.xml中指定
<class name="User">
<cache usage="read-only"/>
....
save,update,saveOrUpdate,list,iterator,get,load以及Query,Criteria都会填充二级缓存,但是只有Session的iterator,get,load会从二级缓存中查询数据。
统计信息打开generate_statistics,用sessionFactory.getStatistics()获取统计信息。
SessionFactory.evict(User.class)/SessionFactory.evict(User.class,id)清除缓存。
Hibernate首先从一级缓存中寻找,找不到再到二级缓存中寻找。
16、Session是非线程安全,SessionFactory是线程安全的。