回顾:
一对多的集合里存的是持久对象,叫实体;不是值类型;String/Integer等
实体的特征是有自己的oid和映射文件;值类型是没有oid的,不能当成持久对象;一般作为持久对象的属性;
一, 集合映射: (用的很少)
Set是无序的,不能重复的;
Bag是介于Set和List之间的,java里没有,Hibernate模拟的, 它是无序的,但是允许重复的;
List是有序的,元素可以重复;
Map的key是不能重复的,value可以重复;
(1)set映射:
Person 类:name,age,gender,aliases(外号/别名)
<set name="aliases" table="t_aliases"> <!-- 只有集合本身的映射表 -->
<key column="fid"></key> <!--外号表引用person表的主键 -->
<element type="String" column="aliases"></element>
</set>
1,set是对集合本身的声明;table是集合元素(String类型)所存在的表;
既不是po的表,也不是多对多的关联表;在集合映射中,set属性即集合本身对应一个表;
2,fid,是set映射主表的主键上;
3,element,不是PO不是一对多,多对多关系;element没有表明任何的基数关系,而是集合关系;
4,type说明集合里的元素类型,column是元素在set映射表中的字段;
(2)bag映射: 在java里用 List 模拟(不保存下标);
Indexs类 --- Images
<idbag name="images" table="t_images">
<collection-id column="id" type="integer"><!-- 加了一个主键保证记录唯一 -->
<generator class="increment" />
</collection-id>
<key column="fid"></key> <!-- 外键也是可以重复的-->
<element type="String" column="image"></element> <!--集合里的元素是可以重复的 -->
</idbag>
(3)list映射:
Word类 --- descs ; 外键和list-index做联合主键;
<list name="descs" table="t_descs">
<key column="fid"></key> <!-- 外键可以重复-->
<list-index column="listIndex"></list-index> <!--下标也是可以重复的 -->
<element column="descri" type="string"> <!-- desc跟系统重名-->
</list>
(4)map映射:
Dictionary类 --- words map-key是key,element是value, (map.entry类型 key-value)
外键和map-key做联合主键;
<map name="words" table="t_words">
<key column="fid"></key>
<map-key column="word" type="string"></map-key>
<element column="descs" type="string"></element>
</map>
二, 组件映射:(用的很多)
组件也属于值类型的一种,是用户自定义的;
非PO;无oid,不需要单独写映射文件,资源利用很少;
实体映射(PO):基数映射和继承映射;
组件映射(非PO):寄居在实体中,细粒度,不需要单独持久化的对象;
1, 一对一的组件映射:
first-name, last-name 变成一个组件===> name
NamePair:就是一个组件;
可以使我们的代码更易读,更精细;
在映射时作为po的一部分,和po放到一个表里;
Account: aid,actNo,balance,owner, Address
把地址当成寄居在Account里;因为别的类也不用;
把Address的oid去掉;把一对一的关联关系,变成了组合关系;没有oid的非PO;
Account.hbn.xml
address属性的映射:
<component name="addr" class="Address">
<property name="postCode"></property>
<property name="city"></property>
<property name="street"></property>
</component>
能当组件看不当PO看,简单;
2, 一对多的组件映射:
集合映射和组件映射结合起来;
在Account中加上一个Address集合;
private Set addrs=new HashSet();
映射文件:
<set name="addrs" table="t_addrs">
<key column="fid" > <!-- 引用主表的主键作为外键 -->
<composite-element class="Address"> <!-- 集合里的元素是一个对象,不是普通的element-->
<property name="postCode"></property>
<property name="city"></property>
<property name="street"></property>
</composite-element>
</set>
注: Hibernate的配置文件里.同一个类只能有一个映射文件;
三, 获得session的方法:
hibernate 3.1 在SessionFactory 中提供了一个方法;
getCurrentSession() 获得当前线程的session;如果第一次调用,
会给你创建一个session;下次再用的话,直接得到这个session;
跟显示调用ThreadLocal不同的是,当事务一结束,即提交或回滚时,自动关闭session;
不需要显式关闭; 一事务一session;
Session s=(Session)sf.getCurrentSession();
tran.commit();//提交后再用session的话,还会再创建一个;开始的是一个新的事务;
// 保证的是一个事务一个session
Dao里不能提交(以方法为单位),放在Services里(以业务的原子操作为单位)提交;
应用事务开启--数据库事务开启---应用事务关闭(数据库事务关闭)
注:
在hibernate的配置文件里需要配置绑定在哪里?JPA(分布式事务管理器)或session;
<property name="current_session_context_class">thread</property>
四, 查询:
1, 有很多记录要查询时:
public static List findByNames(List l){
Session s=HbnUtil.getCurrentSession();
Transaction tran = null;
List result = null;
tran=s.beginTransaction();
Query q=s.createQuery("from Account a where a.owner in(:namelist)");
q.setParameterList("namelist", l );
result = q.list();
tran.commit();
return result;
}
2,属性查询
有时进行查询时不需要得到对象的所有属性,这时我们可以进行属性查询
Query query = session.createQuery(" select p.name from Person p " );
利用这种HQL语句查询出来的结果中,就只包含需要的指定的属性值
如果查询两个以上的属性值时,查询出来的结果会以数组的方式返回
Query query = session.createQuery(" select p.name , p.age from Person as p ");
List list = query.list();
for(int i=0; i<list.size(); i++){
Object obj[] = (Object[])list.get(i);
System.out.println("name===="+ obj[0]);
System.out.println("age ===="+ obj[1]);
}
3,实例化查询:
实例化查询其实是对属性查询的一种改进,示例如下:
Query query = session.createQuery(" select new Person(p.name , p.age) from Person p");
List list = query.list();
for(int i=0; i<list.size(); i++){
Person p = (Person)list.get(i);
System.out.println("name===="+ p.getName() );
System.out.println("age ===="+ p.getAge() );
}
4, 分页查询:
利用hibernate提供的setFirstResult()和setMaxResults()两个方法可以很好的定位
结果集中要查询记录的位置,是分页显示的一种较好的实现方案.
public static List readPage(int start , int num){
Session s=HbnUtil.getCurrentSession();
Transaction tran = null;
List result = null;
tran=s.beginTransaction();
Query query = session.createQuery(" from 实体类名 " );
query.setFirstResult(start); //设置查询记录开始行
query.setMaxResults(num); //设置查询的多少行记录
return query.list() ;
}
补充: rownum只能用<或<=; 可以用起别名的方式来达到目的;
--查询第1-5条记录
select * from (select rownum num, s_emp.* from s_emp)
where num >=1 and num <= 5;
--按工资排序,五条一页,查找第二页
select salary,first_name
from(
select s.*, rownum rm
from (select *
from s_emp
order by salary desc
) s
)
where rm between 6 and 10;
复习:
一, ORMapping:
ORM:持久化,怎样?
a.串行化(序列化):
b.关系型数据库:
关系: jdbc类:(30)代码量大,不好移植,易出错;
EJB Entity:(60)功能太强大了,部署比较复杂,也不适合;
Hibernate:(80)功能刚好,也不是很复杂,具有移植性;
xml文件, PO, 测试类;
持久化对象的确定;
xml文件的配置;
二, 基数映射:
1,一对一: day02
共享主键,其中一个主键还做外键; 两个<one-to-one>
引用外键, 一个<many-to-one>和一个<one-to-one>
普通属性用<property>
第一个特殊的属性就是<id>
另外关联属性用 <many-to-one>等表示;
<one-to-one>表示了一对一的对应关系;
2,一对多:day03
一的一方强的级联;多的一方弱的级联;cascade
inverse=true;交给多的一方去处理关系;
3, 多对多:day04
有一个中间表
三,继承映射:day04
四,组件映射:day05
五,状态:
session: 一级缓存;保持同步;
sessionFactory:二级缓存, 只读不写的话,可以把二级缓存打开,否则没用;
作业:
类图: User 1 ---- m Account --- Address(改成组件映射)
m / / \
1 权限 m Debit Check m
/ \
1 in-policy O-policy 1
(存款政策) 透支政策(一个透支政策可以给多个check使用)
Account:
<many-to-one>
<component>
<subclass>
关键是多练习.大概知道是怎么回事就行了.
只有写与不写的区别,没有会与不会的区别.
五万行代码;
明天讲html和javascript