* 集合映射
如果实体类有一个集合类型的属性,就需要一张额外的表,即所谓的集合表,这
个表有一个外键引用实体类对应的表的主键。
根据集合中存放的元素类型可以分为两种:1,值类型集合,元素是可识别的数据
库类型,如基本数据类型或字符串类型等;2,实体类型集合,元素是其他的实体。
** 对集合做映射时一般需要指定:
1)集合表的表名,在相应元素中使用属性table指定;
2)集合外键,是在子元素key中用属性column属性指定一个列名,他是一个外键
3)集合元素,对于值类型集合,使用元素element指定;对于实体类型集合,使
4)如果是索引集合,如List,数组或Map(bag不是),还需要指定一个集合表中
*** 注意
JAVA的实体类中集合只能定义成接口不能定义成具体类,因为在运行时集合会被
替换成Hibernate的实现。
在实体类中声明集合时,可进行初始化。比如Set addresses = new HashSet();
这样做的目的是方便往集合中添加元素,调用getAddresses().add(element)就可
以了,不需再做是否为null的判断。
HashSet的实例,在运行时,集合会被Hibernate替换为自已的实现。
用于映射集合类的元素是由集合接口的类型决定的:
1,Set,一个用户(User)有多个地址,地址是字符串类型的。
2,List,与Set相比,需要在表中增加一列用于保存索引(元素在List中保存的
3,Map,需要映射key的value:
* 一对多与多对一映射:User与Group
在User.hbm.xml中增加:
在Group.hbm.xml中增加:
这是做的双向关联,即从任何一方都可以得到另一方(User.getGroup得到所属的
组或Group.getUsers得到组中所有的用户);双方也都可以维护关系,维护关系
是指更新外键这一列的的值; 如果只有一方进行映射,就是单向关联。 如果去
掉了User.hbm.xml中的many-to-one映射,只有Group.hbm.xml中有一个set的映射,
这就是单向一对多关联,这时只能由Group维护关系,并且只能从Group得到User。
同样,如果只去掉Group.hbm.xml中的set映射,就是单向多对一关联。
树形结构,就是自己和自己是一个 一对多/多对一 的关系。如Group有父组和子组,
映射文件中为:
* 索引(有序)集合
例如Group中的users希望以user的age升序排列.
有两种方式实现:
有序集合对于List或数组无效,因为列表元素的顺序由列表索引指明。
如果使用的是Set或Map类型的集合,并且在实体中对这个集合属性进行了初始化,
应是SortedSet或SortedMap实现类的实例(TreeSet或TreeMap)。
** sort属性
可以用于set或map映射,默认为unsorted,即不排序;可以设为natural,要求实
体要实现java.lang.Comparable接口。分类集合的行为象TreeSet或者TreeMap,
这是从数据库中取出记录后再在内存中进行排序。(在查询时有效)
** order-by属性
在set、bag或map映射中使用order-by属性,指定查询时生成的sql的order by子
句,这是在执行sql查询时指定排序(推荐)。如果使用了order-by,则返回的就
是可以保存顺序的集合实现类。
* 一对一映射:User与IdCard
有两种映射方式:基于主键和一对一和基于外键和一对一(先分析对象中应怎么
表示(各有一个属性),再用分析数据库表应怎么设计)。不管哪种方式,都是有
外键的那个表对应的实体(IdCard)来维护关系;只为只有IdCard能维护关系,所
以如果要做单向关联,只能做从IdCard到User的单向关联。
不管是多对一还是一对一,有外键的那个表所对应的实体始终能够维护关系。
** 基于主键的一对一
在IdCard.hbm.xml中把主键生成策略改为foreign,并设置one-to-one:
在User.hbm.xml中增加:
** 基于外键的一对一
在IdCard.hbm.xml中增加:
在User.hbm.xml中增加:
* 多对多映射:Group与Privilege
在Group.hbm.xml中增加:
在Privilege.hbm.xml中增加:
双方一定要在set元素中指定相同的表名(这是指定的中间表的名字)。元素
many-to-many 的class 属性用于指定关联类(集合中的实体元素)的名称;因为
是多对多,关联类在中间表中也是用一个外键指定的,many-to-many中的column
属性用于指定这个外键的列名。
这是做的双向关联,此时双方都可以维护关系。多对多中的维护关系是指操作中
间表(增加与删除)的记录。去掉任何一方的映射,就是单向的多对多关联。
如果想要清空Group中含有的Role,可以使用:
这样在提交事务时会删除相应的中间表记录。
* inverse
此属性表示 "是否放弃维护关联关系",在one-to-many和many-to-many中使用,
默认值是"false"。
的数据产生影响。在一对多/多对一中,是指设置外键列的值;在多对多中是指在
中间表是增减记录。
设置inverse=true表示放弃维护关联关系,即由对方来维护。在使用时要注意:
维护关联关系总结:
* cascade
Casade用来说明当对主对象进行某种操作时是否对其关联的从对象也作类似的操
作,常用的cascade值有:
其他还有lock,refresh,evict,replicate,persist,merge,delete-orphan等。
同时使用多种级联风格时使用逗号分隔,如 cascade="save-update,delete"。
通常在many-to-one或many-to-many关系中应用级联没有意义。如删除一个用户不
应该删除他所属的组(组中的其他用户怎么办);或删除了一个组不应该把他对
应的权限实体也删除掉(其他组还要用呢)。 一般在one-to-one和one-to-many
中设置级联比较有用。
* 在Set中添加重复的未保存状态的实体
在一对多中,可以通过设置级联 cascade="save-update" 来实现在save()一方的
实体时级联的插入多方的数据,但这时如果集合如果使用的是Set,就会出现只插
入一个记录的现象,这是因为未保存的对象的主键值相等,hashCode()相同并且
equals()为true。
在Set中不能添加重复的元素,是否重复是通过hashCode和equals方法决定的。所
以可以通过重写hashCode与equals方法实现在Set中可以添加多个未保存的实体对
象(有相同的主键值): hashCode:IF id==null THEN return super.hashCode。
* 集合的lazy属性
延迟加载,默认值为true,即集合的属性值默认是不加载的。强制加载可以通过
在session环境中使用这个集合属性或者使用:Hibernate.initialize(proxy)。
当相关联的session关闭后,再访问懒加载的对象将出现异常。
** get 与 load 方法
get 方法:立即加载。
load方法:延迟加载。
区别:
* 继承映射
论坛中的文章有主题和回复两种:Topic和Reply,他们都是文章,都有content与
author属性,即继承自同一个父类。
可以使用两种方式映射:
** 每个继承结构一张表 (subclass)
<class name="Article" table="itcast_article" discriminator-value="A">
...
<!-- 指定一个列,用于区分子类的具体类型(鉴别器) -->
<discriminator column="class" type="string"></discriminator>
...
<subclass name="Topic" discriminator-value="T">
</subclass>
<subclass name="Reply" discriminator-value="R">
</subclass>
1,指定一个列,用于存放代码类型的标志。
2,为此继承结构中的每一个实体类都指定一个唯一的标志:
** 每个类一张表 (joned-subclass)
...
<joined-subclass name="Topic" table="itcast_topic">
</joined-subclass>
...
其中key指定的是子类表的主键,同时也会做为外键引用父类表的主键。
** 获取实体
使用 session.get(Article.class, 1); 即可返回相应类型的对象实例。
* 查询
Hibernate提供的查询方式有:HQL或Criteria。
** HQL
1,HQL是面向对象的查询语言,他查的是对象而不是表;
2,HQL中的对象名和属性名是区分大小写的(他部分不区分大小写);
3,HQL主要通过Query来操作,Query的创建方式:session.createQuery(hql);
*** 1,from 子句
例:查询所有User实体:
或
1,from后指定的是要查询的实体的名字;
2,如果没有指定entity-name,在from后应写类的全限定名;
3,可以为查询的实体指定一个别名,使用as关键字,但as关键字也可以省略。例:
*** 2,select 子句
例:查询所有User实体:
1,以上是查询整个实体(所有属性,返回的是实体对象);
2,也可以只查询几个属性,指定要查询的属性即可,多个属性之间用逗号隔开,
3,可以让查询部分属性的语句返回结果是一个个相应对象实例,只填充了查询中
小问题:
问题原因:
*** 3,where 子句
例,查询所有id值小于10的User:
1,其中的 u.id 是指的实体的属性;
2,如果属性名与关键字冲突的话,就需在前面加上实体的别名,如u.order或
*** 4, order by
例:from User u order by u.id desc
1,升序:asc;降序:desc ;
2,多个排序属性之间用逗号隔开。
*** 5.聚集函数
avg(),count(),max(),min(),sum()
例,查询所有用户的总数:
执行后,返回的结果可能是Integer类型,也可能是Long型,这是由jdbc驱动决定
的,所以使用时要注意。可以把返回值转为Number,然后根据需要取intValue或
longValue,代码为:((Number) result).intValue();
1,大多数sql的表达式在where子句中都允许使用;
2,Hibernate还提供有操作集合的函数,如:
例1:查询用户数量大于2的所有的组,hql如下:
例2:查询含有某个权限的组:
*** 使用参数
有两种方式:
1,使用?占位,例:from User where id > ?,指定参数值使用
Query.setParameter(int position, Object val),位置索引从0开始;
2, 或使用变量名占位,例:from User where id > :id,指定参数值是使用
Query.setParameter(String name, Object val);
两种方法不能同时使用。
*** Query的分页支持和查询的方法
Query.list()
Query.iterate()
Query.uniqueResult()
分页是通过Query.setFirstResult() 与Query.setMaxResults() 实现。
*** 练习
1, 根据用户名和密码查询一个用户.
2, 查询有指定权限的组.
3, 树形的Group中, 方法 findGroups(Group parent) 查询指定Group的所有子组,
* Criteria 与 DetachedCriteria
Criteria是一种比HQL更面向对象的查询方式。
*** Criteria的创建方式:
*** 添加过滤条件:
*** 指定排序:
*** 分页:
二级缓存:配置:二级缓存是SessionFactory级别的全局缓存,它底下可以使用
不同的缓存类库,hibernate内置了对EhCache, OSCache, TreeCache,
SwarmCache的支持,可以通过实现CacheProvider和Cache接口来加入Hibernate
不支持的缓存实现。使用时要在hibernate.cfg.xml中增加配置:
其中内置的缓存实现在文档19.2. The Second Level Cache中有说明。
以上只是说明可以使用二级缓存,具体的使用是每个类的缓存单独存放,也需要
单独配置。
或在映射文件的class元素加入子元素:
其中usage:read-only,read-write,nonstrict-read-write,transactional。如果
应用程序只需读取一个持久化类的实例,而无需对其修改,应可以对其进行只读
(read-only)缓存;如果应用程序需要更新数据,那么使用读/写缓存(read-write)
比较合适。