hibernate映射2
* inverse
此属性表示 "是否放弃维护关联关系",在one-to-many和many-to-many中使用,
默认值是"false"。 维护关联关系是指在Java里两个对象关联时,对数据库表中
的数据产生影响。在一对多/多对一中,是指设置外键列的值;在多对多中是指在
中间表是增减记录。
设置inverse=true表示放弃维护关联关系,即由对方来维护。在使用时要注意:
a) 在索引(有序)集合中,不要设置inverse=true,否则不能生成索引值。
b) 在多对多映射中,不要双方都设置为inverse=true,否则都不维护关系。
维护关联关系总结:
a) 一对多/多对一:多的一方始终可以维护关系;一的一方可以设置是否维护
关联关系。
b) 一对一:只能由 有外键的表对应的实体 来维护关联关系。
c) 多对多:双方都可以设置是否维护关联关系。
* cascade
Casade用来说明当对主对象进行某种操作时是否对其关联的从对象也作类似的操
作,常用的cascade值有:
none(默认值,无级连操作);
all(所有级连操作);
save-update(对主对象调用save()或update()或saveOrUpdate()方法时对从对
象调用saveOrUpdate());
delete(delete()方法);
其他还有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。
* 继承映射
论坛中的文章有主题和回复两种:Topic和Reply,他们都是文章,都有content与
author属性,即继承自同一个父类。
可以使用两种方式映射:
a) 每个继承结构一张表,需要一个字段用于区分子类的具体类型;
b) 每个类一张表,这是就有三张表,各自都只包含自己的属性,子类对应的表
的主键也做为外键引用超类对应的表的主键。
** 每个继承结构一张表 (subclass)
<class name="Article" table="itcast_article" discriminator-value="A">
...
<!-- 指定一个列,用于区分子类的具体类型(鉴别器) -->
<discriminator column="class" type="string"></discriminator>
...
<subclass name="Topic" discriminator-value="T">
<property name="title"></property>
</subclass>
<subclass name="Reply" discriminator-value="R">
<property name="floor"></property>
</subclass>
discriminator是指定用于区分不同子类的列,type属性指定这个列的类型,如果
不指定,默认为string;这个元素要写在id元素的后面,不要把顺序弄错了。子
类用subclass元素指定,其中的discriminator-value用于指定代表这个子类的值,
这个值要是唯一的。如果不指定,默认值是这个子类的全限定名。
获取实体时,使用:
session.get(Article.class, 1);
返回的记录将会根据这条记录的鉴别器值进行判断返回相应的对象实例。例如,
如果是T,返回一个Topic的实例;如果是R,则返回一个Reply的实例。
** 每个类一张表 (joned-subclass)
...
<joined-subclass name="Topic" table="itcast_topic">
<key column="id"></key>
<property name="title"></property>
</joined-subclass>
...
其中key指定的是子类表的主键,同时也会做为外键引用父类表的主键。
* 查询
Hibernate提供的查询方式有:HQL或Criteria。
** HQL
HQL是面向对象的查询语言,他查的是对象而不是表。HQL中的对象名和属性是区
分大小写的(除了JAVA类和属性其他部分不区分大小写)。HQL主要通过Query来
操作,Query的创建方式:Query q = session.createQuery(hql);
查询所有User实体:
from User
要查询的实体的名字应是全限定名,除非映射文件中的hibernate-mapping的
auto-import属性的值为true,才可以使用非全限定名(默认值为true)。如果系
统中存在多个重名(非全限定名相同)的情况下,应把auto-import都设为false。
实现上面的功能也可以写成:
select u from User as u
这里使用as关键字指了一个别名u,其中as关键字可以省略。
使用where子句进行过滤,例如查询所有id值小于10的User:
from User u where u.id < 10
其中的u.id是指的实体的属性(而非他映射的列名)。如果属性名与关键字冲突
的话,就在前面加上实体的别名,例如u.order或u.desc等。
也可以只查询几个属性,例如只查询所用户名的id和name属性:
select u.id,u.name from User u
这时返回的每一结果都是一个Object数组,数组的第一个元素是id的值,第二个
元素是name的值。
让上面的查询返回是一个个User对象,只填充了id和name的属性:
select new User(u.id,u.name) from User u
这样要求User对象有一个只接受id和name的构造方法:
public User(int id, String name)
可以使用order by指定排序,如 from User u order by u.id desc .
可以使用聚集函数:count(),max(),min()等。例如查询所有用户的总数:
select count(u) from User u
注意,这里返回的值可能是Integer类型,也可能是Long型,这是由jdbc驱动决定
的,所以使用时要注意。
大多数sql的表达式在where子句中都允许使用。Hibernate还提供有操作集合的函
数:size(),集合的大小; maxelement()和minelement(),引用一个基本数据类
型的集合中的最大与最小的元素;minindex()与maxindex(),引用有序集合的最
小与最大的索引;elements(),返回集合的元素;等等,他们都需要一个集合类
型的参数。如查询含有某个用户的组:
from Group g where ? in elements(g.users)
还在设置一个参数,值为一个User的一个对象实例。
** Query的使用,参数与分页
Query.list()是返回一个List集合;
Query.iterate()返回一个Iterator,这是先查询出所有的id,再一条一条的查询
记录,这种方式查询可以使用缓存;
Query.uniqueResult是返回唯一的结果或null(无匹配时),如果有多条记录匹
配,则抛异常NonUniqueResultException。
使用参数的两种方式:1,使用?占位,例:from User where id > ? .指定参数
值是使用Query.setParameter(int position, Object val),位置索引从0开始;
或使用变量名占位,例:from User where id > :id,指定参数值是使用
Query.setParameter(String name, Object val);
分页是通过Query.setFirstResult() 与Query.setMaxResults() 实现。
**
查找所有属于指定组的用户:
session.createQuery("from User u where u.group = ?")
.setParameter(0, group)
.list();
查找所有属于 名字为'xx'的组的 用户:
session.createQuery("from User u where u.group.name = 'xx'")
.list();
* Criteria 与 DetachedCriteria
Criteria是一种比HQL更面向对象的查询方式。
Criteria的创建方式:
Criteria c = session.createCriteria(User.class);
添加过滤条件:
c.add(Restrictions.gt("id",3)); // id的值要大于3
c.add(Restrictions.isNull("desc")); // desc不能为空
这样添加的条件之间是 and 的关系。添加or关系的条件使用:
c.add(Restrictions.or(Restrictions.eq("name", "xx"),
Restrictions.eq("name", "yy")));
这是查询名字为'xx'或'yy'的组。
指定排序:
c.addOrder(Order.desc("id")); // 按id的值降序排列
分页:
Criteria.setFirstResult(0);
Criteria.setMaxResults(10);
**
查找所有属于指定组的用户:
Criteria c = session.createCriteria(User.class);
c.add(Restrictions.eq("group", group));
查找所有属于 名字为'xx'的组的 用户:
Criteria c = session.createCriteria(User.class);
c.createAlias("group", "g"); // 创建连接查询
c.add(Restrictions.eq("g.name", "xx"));
** DetachedCriteria
DetachedCriteria可在session外创建(在其他层创建比如在Service中创建)然
后用getExecutableCriteria(session)方法创建Criteria对象来完成查询。
* 缓存
缓存的作用主要用来提高性能,可以简单的理解成一个Map;
class Xxx{
Map<Integer, Object> cache = new HashSet<Integer, Object>();
public User get(int id){
User user = cache.get(id);
if(user == null){
user = "select from database";
cache.put(user.getId(), user);
}
return user
}
}
一级缓存,Session级共享。每个Session会在内部维护一个数据缓存,此缓存随
着Session的创建/销毁而创建/销毁。save, update, saveOrUpdate, load,
get, list, iterate等这些方法都会将对象放在一级缓存中,一级缓存不能控制
缓存的数量,所以要注意大批量操作数据时可能造成内存溢出;可以用evict,
clear方法清除缓存中的内容。
二级缓存:配置:二级缓存是SessionFactory级别的全局缓存,它底下可以使用
不同的缓存类库,hibernate内置了对EhCache, OSCache, TreeCache,
SwarmCache的支持,可以通过实现CacheProvider和Cache接口来加入Hibernate
不支持的缓存实现。使用时要在hibernate.cfg.xml中增加配置:
<property name="cache.provider_class">
org.hibernate.cache.HashtableCacheProvider
</property>
其中内置的缓存实现在文档19.2. The Second Level Cache中有说明。
以上只是说明可以使用二级缓存,具体的使用是每个类的缓存单独存放,也需要
单独配置。 使用方式为:在hibernate.cfg.xml中增加:
<class-cache usage="read-only"/>
或在映射文件的class元素加入子元素:
<cache usage="read-write"/>
其中usage:read-only,read-write,nonstrict-read-write,transactional。如果
应用程序只需读取一个持久化类的实例,而无需对其修改,应可以对其进行只读
(read-only)缓存;如果应用程序需要更新数据,那么使用读/写缓存(read-write)
比较合适。
* 事务
通过配置current_session_context_class 来使用
SessionFactory.getCurrentSession,这样会始终返回一个Session;或自己用
ThreadLocal实现,用ThreadLocal实现的好处是可以在没有对应Session时选择是
否创建。