??xml version="1.0" encoding="utf-8" standalone="yes"?> 它有两种配置方式OpenSessionInViewInterceptor?span style="font-size: 10pt; color: #4b4b4b; font-family: Verdana">OpenSessionInViewFilter(具体参看SpringSide)
Open Session In View?/span>request?/span>sessionl定到当?/span>thread期间一直保?/span>hibernate session?/span>open状态,?/span>session?/span>request的整个期间都可以使用Q如?/span>View层里PO也可?/span>lazy loading数据Q如 ${ company.employees }。当View 层逻辑完成后,才会通过Filter?/span>doFilterҎ?/span>Interceptor?/span>postHandleҎ自动关闭session?/span>
OpenSessionInViewInterceptor配置
OpenSessionInViewFilter配置
很多人在使用OpenSessionInViewq程中提及一个错误:
看看OpenSessionInViewFilter里的opensessionҎ
可以看到OpenSessionInViewFilter在getSession的时?会把获取回来的session的flush mode 设ؓFlushMode.NEVER。然后把该sessionFactoryl定到TransactionSynchronizationManagerQrequest的整个过E都使用同一个sessionQ在hq后再接除该sessionFactory的绑定,最?span class="me1">closeSessionIfNecessaryҎ该session是否已和transactionl定来决定是否关闭session。在q个q程中,若HibernateTemplate 发现自当前session有不是readOnly的transactionQ就会获取到FlushMode.AUTO SessionQҎ拥有写权限?/p>
也即是,如果有不是readOnly的transaction可以由Flush.NEVER转ؓFlush.AUTO,拥有insert,update,delete操作权限Q如果没有transactionQƈ且没有另外h为地设flush model的话Q则doFilter的整个过E都是Flush.NEVER。所以受transaction保护的方法有写权限,没受保护的则没有?/p>
采用spring的事务声?使方法受transaction控制
对于上例Q则以save,add,update,remove开头的Ҏ拥有可写的事务,如果当前有某个方法,如命名ؓimportExcel()Q则因没有transaction而没有写权限Q这时若Ҏ内有insert,update,delete操作的话Q则需要手动设|flush model为Flush.AUTO,?/p>
管Open Session In View看v来还不错Q其实副作用不少。看回上面OpenSessionInViewFilter的doFilterInternalҎ代码Q这个方法实际上是被父类的doFilter调用的,因此Q我们可以大U了解的OpenSessionInViewFilter调用程: request(h)->open sessionq开始transaction->controller->View(Jsp)->l束transactionqclose session.
一切看h很正,其是在本地开发测试的时候没出现问题Q但试想下如果流E中的某一步被d的话Q那在这期间connection׃直被占用而不释放。最有可能被d的就是在写Jspq步Q一斚w可能是页面内容大Qresponse.write的时间长Q另一斚w可能是网速慢Q服务器与用户间传输旉久。当大量q样的情况出现时Q就有连接池q接不Q造成面假死现象?/p>
Open Session In View是个双刃剑,攑֜公网上内容多量大的|站h用?/p>
hibernate open session in view 抛出异常解决Ҏ
在用open-session-in-view的时候,如果使用不当Q有可能抛出两种异常
1QNonUniqueObjectException
2Q在配合spring使用的时候会可能会抛出org.springframework.dao.InvalidDataAccessApiUsageException
先说1Q这个异常的抛出原因和解军_法见q里Q?br />
javaeye上有了很好的事例:http://www.javaeye.com/topic/11581
解决办法可以用mergeQ也可以别的办法?br />
出现的原因,可以参考一下我前边的文章中merge和update的区别的内容?br />
http://m.tkk7.com/dreamstone/archive/2007/07/29/133071.html
2的解军_法:在这?br />
springside的一文章做了详l说?br />
http://calvin.blog.javascud.org/post/46.htm
好了Q现在问题解决了Q但关于open-session-in-view的用还有一些探讨,是否应该使用Q用的好处与坏处?br />
见这两篇jdon上的文章:
http://www.jdon.com/jivejdon/thread/22374.html
http://www.jdon.com/jivejdon/thread/28955.html
实体对象的gq加?
1.在hibernate配置文g中的class指定
集合cd的gq加载:
在set中指定lazy=true
q样只有实际加蝲与对象相兌的集合对象的时候,再通过session从数据库中加载实际的数据集?br />
Hibernate.initializeҎ可以强制Hibernate立即加蝲兌的对象集Q例如:
Hibernate.initialize(user.getAddress());
集合cd的缓存:
如果为某个集合类讑֮了缓存,?br />
<set
name="address"
table="t_address"
lazy="true"
......
>
<cache usage="read-only"/>
<key column="user_id" />
<one-to-many class="cn.blogjava.TAddress" />
</set>
Hibernate寚w合类型进行缓存的时候,分两部分保存。首先是q个集合中所有实体的id列表Q其ơ才是各个实体对象?br />
q里制定了cache usage="read-only"只会使得HibernateҎ据烦引进行缓存。也是说只~存了集合中的数据烦引,q不包含集合中的各个实体元素?br />
如果指定cache usage="read-write"才会寚w合中的实体进行缓存?/p>
属性的延迟加蝲Q?br /> 在property节点中声明lazy=true,而且q需要借助Hibernatecd强器对POJOcȝ二进制Class文gq行强化处理?/p>
hibernate中的Collection
Hibernate对JDK Collention接口的独立实玎ͼ
׃传统的Java Set, Map, List实现不能满要求QHibernateҎq些接口提供了自q实现?br />
Hibernate的实玎ͼ
无序集:Set, Bag, Map
有序集:List
Bag相当于一个允讔R复元素存在的Set?br />
因ؓHibernate是自qCollection实现Q所以如下语句会出错Q?br />
Set hset = (HashSet)user.getAddresses();
会在q行期报告一个java.lang.ClassCastException,因ؓ实际上返回的是一个类型ؓorg.hibernate.collention.Set的对象?br />
所有我们在写POJOӞ必须用JDK Collection Interface(如Set, Map)Q而非特定的JDK Collection实现c?如HashSet, HashMap)声明Collection型属性的原因。例如:
应该是private Set addresses;
而不是private HashSet addresses;
collectioncd属性的保存q程?br />
例如
public class TUser implements Serializable {
private Set addresses = new HashSet();
......
}
然后创徏一个TUser实例后,可以ؓ其添加关联的address对象Q?br />
TUser user = new TUser();
TAddress addr = new TAddress();
addr.setAddress("HongKong");
user.getAddress().add(addr);
session.save(user);
user对象在经qHibernate处理后发生了变化Q首先,׃insert操作Q生了id|q填充到user对象的id属性,另一斚wHibernate使用了自qcollection实现对user中的HashSet型addresses属性进行了替换Qƈ用数据对其进行了填充?/p>
延迟加蝲Q?/span>
延迟加蝲机制是ؓ了避免一些无谓的性能开销而提出来的,所谓gq加载就是当在真正需要数据的时候,才真正执行数据加载操作。在Hibernate中提供了对实体对象的延迟加蝲以及寚w合的延迟加蝲Q另外在Hibernate3中还提供了对属性的延迟加蝲。下面我们就分别介绍q些U类的gq加载的l节?/span>
A?/span>实体对象的gq加载:
如果惛_实体对象使用延迟加蝲Q必要在实体的映射配置文g中进行相应的配置Q如下所C:
<hibernate-mapping>
<class name=”com.neusoft.entity.User” table=”user” lazy=”true”>
……
</class>
</hibernate-mapping>
通过?/span>class?/span>lazy属性设|ؓtrueQ来开启实体的延迟加蝲Ҏ。如果我们运行下面的代码Q?/span>
User user=(User)session.load(User.class,”1”);Q?/span>1Q?/span>
System.out.println(user.getName());Q?/span>2Q?/span>
当运行到(1)处时Q?/span>Hibernateq没有发起对数据的查询,如果我们此时通过一些调试工?/span>(比如JBuilder2005?/span>Debug工具)Q观察此?/span>user对象的内存快照,我们会惊奇的发现Q此时返回的可能?/span>User$EnhancerByCGLIB$$bede8986cd的对象,而且其属性ؓnull,q是怎么回事Q还记得前面我曾讲过session.load()ҎQ会q回实体对象的代理类对象Q这里所q回的对象类型就?/span>User对象的代理类对象。在Hibernate中通过使用CGLIB,来实现动态构造一个目标对象的代理cd象,q且在代理类对象中包含目标对象的所有属性和ҎQ而且所有属性均被赋gؓnull。通过调试器显C的内存快照Q我们可以看出此时真正的User对象Q是包含在代理对象的CGLIB$CALBACK_0.target属性中Q当代码q行刎ͼ2Q处Ӟ此时调用user.getName()ҎQ这旉过CGLIB赋予的回调机Ӟ实际上调?/span>CGLIB$CALBACK_0.getName()ҎQ当调用该方法时Q?/span>Hibernate会首先检?/span>CGLIB$CALBACK_0.target属性是否ؓnullQ如果不为空Q则调用目标对象?/span>getNameҎQ如果ؓI,则会发v数据库查询,生成cMq样?/span>SQL语句Q?/span>select * from user where id=’1’;来查询数据,q构造目标对象,q且它赋值到CGLIB$CALBACK_0.target属性中?/span>
q样Q通过一个中间代理对象,Hibernate实现了实体的延迟加蝲Q只有当用户真正发v获得实体对象属性的动作Ӟ才真正会发v数据库查询操作。所以实体的延迟加蝲是用通过中间代理cd成的Q所以只?/span>session.load()Ҏ才会利用实体延迟加蝲Q因为只?/span>session.load()Ҏ才会q回实体cȝ代理cd象?/span>
B?span style="FONT: 7pt Times New Roman"> 集合cd的gq加载:
?/span>Hibernate的gq加载机制中Q针寚w合类型的应用Q意义是最为重大的Q因有可能性能得到大幅度的提高Qؓ?/span>Hibernateq行了大量的努力Q其中包括对JDK Collection的独立实玎ͼ我们在一对多兌中,定义的用来容U_联对象的Set集合Qƈ不是java.util.Setcd或其子类型,而是net.sf.hibernate.collection.SetcdQ通过使用自定义集合类的实玎ͼHibernate实现了集合类型的延迟加蝲。ؓ了对集合cd使用延迟加蝲Q我们必d下配|我们的实体cȝ关于兌的部分:
<hibernate-mapping>
<class name=”com.neusoft.entity.User” table=”user”>
…..
<set name=”addresses” table=”address” lazy=”true” inverse=”true”>
<key column=”user_id”/>
<one-to-many class=”com.neusoft.entity.Arrderss”/>
</set>
</class>
</hibernate-mapping>
通过?/span><set>元素?/span>lazy属性设|ؓtrue来开启集合类型的延迟加蝲Ҏ。我们看下面的代码:
User user=(User)session.load(User.class,”1”);
Collection addset=user.getAddresses(); (1)
Iterator it=addset.iterator(); (2)
while(it.hasNext()){
Address address=(Address)it.next();
System.out.println(address.getAddress());
}
当程序执行到(1)处时Q这时ƈ不会发v对关联数据的查询来加载关联数据,只有q行?/span>(2)处时Q真正的数据d操作才会开始,q时Hibernate会根据缓存中W合条g的数据烦引,来查扄合条件的实体对象?/span>
q里我们引入了一个全新的概念——数据烦引,下面我们首先接一下什么是数据索引。在Hibernate中对集合cdq行~存Ӟ是分两部分进行缓存的Q首先缓存集合中所有实体的id列表Q然后缓存实体对象,q些实体对象?/span>id列表Q就是所谓的数据索引。当查找数据索引Ӟ如果没有扑ֈ对应的数据烦引,q时׃一?/span>select SQL的执行,获得W合条g的数据,q构造实体对象集合和数据索引Q然后返回实体对象的集合Qƈ且将实体对象和数据烦引纳?/span>Hibernate的缓存之中。另一斚wQ如果找到对应的数据索引Q则从数据烦引中取出id列表Q然后根?/span>id在缓存中查找对应的实体,如果扑ֈ׃~存中返回,如果没有扑ֈQ在发vselect SQL查询。在q里我们看出了另外一个问题,q个问题可能会对性能产生影响Q这是集合cd的缓存策略。如果我们如下配|集合类型:
<hibernate-mapping>
<class name=”com.neusoft.entity.User” table=”user”>
…..
<set name=”addresses” table=”address” lazy=”true” inverse=”true”>
<cache usage=”read-only”/>
<key column=”user_id”/>
<one-to-many class=”com.neusoft.entity.Arrderss”/>
</set>
</class>
</hibernate-mapping>
q里我们应用?/span><cache usage=”read-only”/>配置Q如果采用这U策略来配置集合cdQ?/span>Hibernate只会对数据索引q行~存Q而不会对集合中的实体对象q行~存。如上配|我们运行下面的代码Q?/span>
User user=(User)session.load(User.class,”1”);
Collection addset=user.getAddresses();
Iterator it=addset.iterator();
while(it.hasNext()){
Address address=(Address)it.next();
System.out.println(address.getAddress());
}
System.out.println(“Second query……”);
User user2=(User)session.load(User.class,”1”);
Collection it2=user2.getAddresses();
while(it2.hasNext()){
Address address2=(Address)it2.next();
System.out.println(address2.getAddress());
}
q行q段代码Q会得到cM下面的输出:
Select * from user where id=’1’;
Select * from address where user_id=’1’;
Tianjin
Dalian
Second query……
Select * from address where id=’1’;
Select * from address where id=’2’;
Tianjin
Dalian
我们看到Q当W二ơ执行查询时Q执行了两条?/span>address表的查询操作Qؓ什么会q样Q这是因为当W一ơ加载实体后Q根据集合类型缓存策略的配置Q只寚w合数据烦引进行了~存Q而ƈ没有寚w合中的实体对象进行缓存,所以在W二ơ再ơ加载实体时Q?/span>Hibernate扑ֈ了对应实体的数据索引Q但是根据数据烦引,却无法在~存中找到对应的实体Q所?/span>HibernateҎ扑ֈ的数据烦引发起了两条select SQL的查询操作,q里造成了对性能的浪费,怎样才能避免q种情况呢?我们必须寚w合类型中的实体也指定~存{略Q所以我们要如下寚w合类型进行配|:
<hibernate-mapping>
<class name=”com.neusoft.entity.User” table=”user”>
…..
<set name=”addresses” table=”address” lazy=”true” inverse=”true”>
<cache usage=”read-write”/>
<key column=”user_id”/>
<one-to-many class=”com.neusoft.entity.Arrderss”/>
</set>
</class>
</hibernate-mapping>
此时Hibernate会对集合cd中的实体也进行缓存,如果Ҏq个配置再次q行上面的代码,会得到cM如下的输出:
Select * from user where id=’1’;
Select * from address where user_id=’1’;
Tianjin
Dalian
Second query……
Tianjin
Dalian
q时不会再有根据数据烦引进行查询的SQL语句Q因为此时可以直接从~存中获得集合类型中存放的实体对象?/span>
C?span style="FONT: 7pt Times New Roman"> 属性gq加载:
?/span>Hibernate3中,引入了一U新的特性——属性的延迟加蝲Q这个机制又取高性能查询提供了有力的工具。在前面我们讲大数据对象dӞ?/span>User对象中有一?/span>resume字段Q该字段是一?/span>java.sql.ClobcdQ包含了用户的简历信息,当我们加载该对象Ӟ我们不得不每一ơ都要加载这个字D,而不论我们是否真的需要它Q而且q种大数据对象的d本n会带来很大的性能开销。在Hibernate2中,我们只有通过我们前面讲过的面性能的粒度细分,来分?/span>Userc,来解册个问题(请参照那一节的Q,但是?/span>Hibernate3中,我们可以通过属性gq加载机Ӟ来我们获得只有当我们真正需要操作这个字D|Q才去读取这个字D|据的能力Qؓ此我们必d下配|我们的实体c:
<hibernate-mapping>
<class name=”com.neusoft.entity.User” table=”user”>
……
<property name=”resume” type=”java.sql.Clob” column=”resume” lazy=”true”/>
</class>
</hibernate-mapping>
通过?/span><property>元素?/span>lazy属性设|?/span>true来开启属性的延迟加蝲Q在Hibernate3中ؓ了实现属性的延迟加蝲Q用了cd强器来对实体cȝClass文gq行强化处理Q通过增强器的增强Q将CGLIB的回调机刉辑Q加入实体类Q这里我们可以看出属性的延迟加蝲Q还是通过CGLIB来实现的?/span>CGLIB?/span>Apache的一个开源工E,q个cd可以操纵javacȝ字节码,Ҏ字节码来动态构造符合要求的cd象。根据上面的配置我们q行下面的代码:
String sql=”from User user where user.name=’zx’ ”;
Query query=session.createQuery(sql); (1)
List list=query.list();
for(int i=0;i<list.size();i++){
User user=(User)list.get(i);
System.out.println(user.getName());
System.out.println(user.getResume()); (2)
}
当执行到(1)处时Q会生成cM如下?/span>SQL语句Q?/span>
Select id,age,name from user where name=’zx’;
q时Hibernate会检?/span>User实体中所有非延迟加蝲属性对应的字段数据Q当执行?/span>(2)处时Q会生成cM如下?/span>SQL语句Q?/span>
Select resume from user where id=’1’;
q时会发起对resume字段数据真正的读取操作?/span>
|
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="mappingResources">
<list>
<value>org/appfteaching/model/TArticleclass.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.jdbc.fetch_size">${hibernate.jdbc.fetch_size}</prop>
<prop key="hibernate.jdbc.batch_size">${hibernate.jdbc.batch_size}</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
</props>
</property>
</bean>
2.其次,在src目录下的ehcache.xml中配|如下信?如果是默认ehcache.xml则会?lt;cache name="sampleCache1">?lt;cache name="sampleCache2>",L)
<cache name="org.hibernate.cache.StandardQueryCache"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="4200"
overflowToDisk="true"
/>
<!-- Sample cache named sampleCache2
This cache contains 1000 elements. Elements will always be held in memory.
They are not expired. -->
<cache name="org.hibernate.cache.UpdateTimestampsCache"
maxElementsInMemory="5000"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false"
/>
3.你要缓存的model加进ehcache.xml?/p>
<cache name="org.appfteaching.model.TArticleclass"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="100"
timeToLiveSeconds="4200"
overflowToDisk="true"
/>
4.最后一?在TArticleclass.hbm.xml里加?/p>
<cache usage="read-write"/>
启动Tomcat,如发现如下错?/p>
Could not find configuration [org.hibernate.cache.UpdateTimestampsCache]; using defaults.
Could not find configuration [org.hibernate.cache.StandardQueryCache]; using defaults.
则是W二步没有做,加上卛_.配置完毕
org.hibernate.Criteria接口表示特定持久cȝ一个查询?tt class=literal>Session?Criteria实例的工厂?
Criteria crit = sess.createCriteria(Cat.class); crit.setMaxResults(50); List cats = crit.list();
一个单独的查询条g?tt class=literal>org.hibernate.criterion.Criterion 接口的一个实例?tt class=literal>org.hibernate.criterion.Restrictionsc?定义了获得某些内|?tt class=literal>Criterioncd的工厂方法?
List cats = sess.createCriteria(Cat.class) .add( Restrictions.like("name", "Fritz%") ) .add( Restrictions.between("weight", minWeight, maxWeight) ) .list();
U束可以按逻辑分组?
List cats = sess.createCriteria(Cat.class) .add( Restrictions.like("name", "Fritz%") ) .add( Restrictions.or( Restrictions.eq( "age", new Integer(0) ), Restrictions.isNull("age") ) ) .list();
List cats = sess.createCriteria(Cat.class) .add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) ) .add( Restrictions.disjunction() .add( Restrictions.isNull("age") ) .add( Restrictions.eq("age", new Integer(0) ) ) .add( Restrictions.eq("age", new Integer(1) ) ) .add( Restrictions.eq("age", new Integer(2) ) ) ) ) .list();
Hibernate提供了相当多的内|criterioncd(Restrictions 子类), 但是其有用的是可以允许你直接用SQL?
List cats = sess.createCriteria(Cat.class) .add( Restrictions.sql("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) ) .list();
{alias}占位W应当被替换查询实体的列别名?
Property实例是获得一个条件的另外一U途径。你可以通过调用Property.forName() 创徏一?tt class=literal>Property?
Property age = Property.forName("age"); List cats = sess.createCriteria(Cat.class) .add( Restrictions.disjunction() .add( age.isNull() ) .add( age.eq( new Integer(0) ) ) .add( age.eq( new Integer(1) ) ) .add( age.eq( new Integer(2) ) ) ) ) .add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) ) .list();
你可以?tt class=literal>org.hibernate.criterion.Order来ؓ查询l果排序?
List cats = sess.createCriteria(Cat.class) .add( Restrictions.like("name", "F%") .addOrder( Order.asc("name") ) .addOrder( Order.desc("age") ) .setMaxResults(50) .list();
List cats = sess.createCriteria(Cat.class) .add( Property.forName("name").like("F%") ) .addOrder( Property.forName("name").asc() ) .addOrder( Property.forName("age").desc() ) .setMaxResults(50) .list();
你可以?tt class=literal>createCriteria()非常Ҏ的在互相兌的实体间建立 U束?
List cats = sess.createCriteria(Cat.class) .add( Restrictions.like("name", "F%") .createCriteria("kittens") .add( Restrictions.like("name", "F%") .list();
注意W二?createCriteria()q回一个新?Criteria实例Q该实例引用kittens 集合中的元素?
接下来,替换形态在某些情况下也是很有用的?
List cats = sess.createCriteria(Cat.class) .createAlias("kittens", "kt") .createAlias("mate", "mt") .add( Restrictions.eqProperty("kt.name", "mt.name") ) .list();
(createAlias()q不创徏一个新?Criteria实例?
Cat实例所保存的之前两ơ查询所q回的kittens集合?没有被条仉qo的。如果你希望只获得符合条件的kittensQ?你必M?tt class=literal>returnMaps()?
List cats = sess.createCriteria(Cat.class) .createCriteria("kittens", "kt") .add( Restrictions.eq("name", "F%") ) .returnMaps() .list(); Iterator iter = cats.iterator(); while ( iter.hasNext() ) { Map map = (Map) iter.next(); Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS); Cat kitten = (Cat) map.get("kt"); }
你可以?tt class=literal>setFetchMode()在运行时定义动态关联抓取的语义?
List cats = sess.createCriteria(Cat.class) .add( Restrictions.like("name", "Fritz%") ) .setFetchMode("mate", FetchMode.EAGER) .setFetchMode("kittens", FetchMode.EAGER) .list();
q个查询可以通过外连接抓?tt class=literal>mate?tt class=literal>kittens?查看W?nbsp;20.1 ?“ 抓取{略(Fetching strategies) ”可以获得更多信息?
org.hibernate.criterion.Examplecd怽通过一个给定实?构徏一个条件查询?
Cat cat = new Cat(); cat.setSex('F'); cat.setColor(Color.BLACK); List results = session.createCriteria(Cat.class) .add( Example.create(cat) ) .list();
版本属性、标识符和关联被忽略。默认情况下gؓnull的属性将被排除?
你可以自行调?tt class=literal>Example使之更实用?
Example example = Example.create(cat) .excludeZeroes() //exclude zero valued properties .excludeProperty("color") //exclude the property named "color" .ignoreCase() //perform case insensitive string comparisons .enableLike(); //use like for string comparisons List results = session.createCriteria(Cat.class) .add(example) .list();
你甚臛_以用examples在关联对象上攄条g?
List results = session.createCriteria(Cat.class) .add( Example.create(cat) ) .createCriteria("mate") .add( Example.create( cat.getMate() ) ) .list();
org.hibernate.criterion.Projections?Projection 的实例工厂。我们通过调用 setProjection()应用投媄C个查询?
List results = session.createCriteria(Cat.class) .setProjection( Projections.rowCount() ) .add( Restrictions.eq("color", Color.BLACK) ) .list();
List results = session.createCriteria(Cat.class) .setProjection( Projections.projectionList() .add( Projections.rowCount() ) .add( Projections.avg("weight") ) .add( Projections.max("weight") ) .add( Projections.groupProperty("color") ) ) .list();
在一个条件查询中没有必要昑ּ的?"group by" 。某些投q型就是被定义?span class=emphasis> 分组投媄Q他们也出现在SQL?tt class=literal>group by子句中?
你可以选择把一个别名指z一个投影,q样可以使投影DU束或排序所引用。下面是两种不同的实现方式:
List results = session.createCriteria(Cat.class) .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) ) .addOrder( Order.asc("colr") ) .list();
List results = session.createCriteria(Cat.class) .setProjection( Projections.groupProperty("color").as("colr") ) .addOrder( Order.asc("colr") ) .list();
alias()?tt class=literal>as()Ҏ便的一个投影实例包装到另外一?别名?tt class=literal>Projection实例中。简而言之,当你d一个投影到一个投影列表中?你可以ؓ它指定一个别名:
List results = session.createCriteria(Cat.class) .setProjection( Projections.projectionList() .add( Projections.rowCount(), "catCountByColor" ) .add( Projections.avg("weight"), "avgWeight" ) .add( Projections.max("weight"), "maxWeight" ) .add( Projections.groupProperty("color"), "color" ) ) .addOrder( Order.desc("catCountByColor") ) .addOrder( Order.desc("avgWeight") ) .list();
List results = session.createCriteria(Domestic.class, "cat") .createAlias("kittens", "kit") .setProjection( Projections.projectionList() .add( Projections.property("cat.name"), "catName" ) .add( Projections.property("kit.name"), "kitName" ) ) .addOrder( Order.asc("catName") ) .addOrder( Order.asc("kitName") ) .list();
你也可以使用Property.forName()来表C投影:
List results = session.createCriteria(Cat.class) .setProjection( Property.forName("name") ) .add( Property.forName("color").eq(Color.BLACK) ) .list();
List results = session.createCriteria(Cat.class) .setProjection( Projections.projectionList() .add( Projections.rowCount().as("catCountByColor") ) .add( Property.forName("weight").avg().as("avgWeight") ) .add( Property.forName("weight").max().as("maxWeight") ) .add( Property.forName("color").group().as("color" ) ) .addOrder( Order.desc("catCountByColor") ) .addOrder( Order.desc("avgWeight") ) .list();
DetachedCriteriacM你在一个session范围之外创徏一个查询,q且可以使用L?Session来执行它?
DetachedCriteria query = DetachedCriteria.forClass(Cat.class) .add( Property.forName("sex").eq('F') ); Session session = ....; Transaction txn = session.beginTransaction(); List results = query.getExecutableCriteria(session).setMaxResults(100).list(); txn.commit(); session.close();
DetachedCriteria也可以用以表C子查询。条件实例包含子查询可以通过 Subqueries或?tt class=literal>Property获得?
DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class) .setProjection( Property.forName("weight").avg() ); session.createCriteria(Cat.class) .add( Property.forName("weight).gt(avgWeight) ) .list();
DetachedCriteria weights = DetachedCriteria.forClass(Cat.class) .setProjection( Property.forName("weight") ); session.createCriteria(Cat.class) .add( Subqueries.geAll("weight", weights) ) .list();
甚至怺兌的子查询也是有可能的Q?
DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2") .setProjection( Property.forName("weight").avg() ) .add( Property.forName("cat2.sex").eqProperty("cat.sex") ); session.createCriteria(Cat.class, "cat") .add( Property.forName("weight).gt(avgWeightForSex) ) .list();
兌关系映射通常情况是最N|正的。在q个部分中,我们从单向关pL开始,然后考虑双向关系映射Q由至pqC遍典型的案例。在所有的例子中,我们都?Person?tt class=literal>Address?
我们Ҏ映射关系是否涉及q接表以及多h来划分兌cd?
在传l的数据建模中,允许为Null值的外键被认为是一U不好的实践Q因此我们所有的例子中都使用不允ؓNull的外键。这q不是Hibernate的要求,即你删除掉不允ؓNull的约束,Hibernate映射一样可以工作的很好?
单向many-to-one兌是最常见的单向关联关pR?
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <many-to-one name="address" column="addressId" not-null="true"/> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> </class>
create table Person ( personId bigint not null primary key, addressId bigint not null ) create table Address ( addressId bigint not null primary key )
Z外键兌的单向一对一兌?span class=emphasis>单向多对一兌几乎是一L。唯一的不同就是单向一对一兌中的外键字段h唯一性约束?
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <many-to-one name="address" column="addressId" unique="true" not-null="true"/> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> </class>
create table Person ( personId bigint not null primary key, addressId bigint not null unique ) create table Address ( addressId bigint not null primary key )
Z主键兌的单向一对一兌通常使用一个特定的id生成器。(h意,在这个例子中我们掉换了关联的方向。)
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> </class> <class name="Address"> <id name="id" column="personId"> <generator class="foreign"> <param name="property">person</param> </generator> </id> <one-to-one name="person" constrained="true"/> </class>
create table Person ( personId bigint not null primary key ) create table Address ( personId bigint not null primary key )
Z外键兌的单向一对多兌是一U很见的情况,q不推荐使用?
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <set name="addresses"> <key column="personId" not-null="true"/> <one-to-many class="Address"/> </set> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> </class>
create table Person ( personId bigint not null primary key ) create table Address ( addressId bigint not null primary key, personId bigint not null )
我们认ؓ对于q种兌关系最好用连接表?
Zq接表的单向一对多兌 应该优先被采用。请注意Q通过指定unique="true"Q我们可以把多样性从多对多改变ؓ一对多?
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <set name="addresses" table="PersonAddress"> <key column="personId"/> <many-to-many column="addressId" unique="true" class="Address"/> </set> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> </class>
create table Person ( personId bigint not null primary key ) create table PersonAddress ( personId not null, addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )
Zq接表的单向多对一兌在关联关pd选的情况下应用也很普遍?
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <join table="PersonAddress" optional="true"> <key column="personId" unique="true"/> <many-to-one name="address" column="addressId" not-null="true"/> </join> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> </class>
create table Person ( personId bigint not null primary key ) create table PersonAddress ( personId bigint not null primary key, addressId bigint not null ) create table Address ( addressId bigint not null primary key )
Zq接表的单向一对一兌非常见Q但也是可行的?
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <join table="PersonAddress" optional="true"> <key column="personId" unique="true"/> <many-to-one name="address" column="addressId" not-null="true" unique="true"/> </join> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> </class>
create table Person ( personId bigint not null primary key ) create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique ) create table Address ( addressId bigint not null primary key )
最后,q有 单向多对多关?/em>.
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <set name="addresses" table="PersonAddress"> <key column="personId"/> <many-to-many column="addressId" class="Address"/> </set> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> </class>
create table Person ( personId bigint not null primary key ) create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) ) create table Address ( addressId bigint not null primary key )
双向多对一兌 是最常见的关联关pR(q也是标准的?子关联关pR)
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <many-to-one name="address" column="addressId" not-null="true"/> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> <set name="people" inverse="true"> <key column="addressId"/> <one-to-many class="Person"/> </set> </class>
create table Person ( personId bigint not null primary key, addressId bigint not null ) create table Address ( addressId bigint not null primary key )
Z外键兌的双向一对一兌也很常见?
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <many-to-one name="address" column="addressId" unique="true" not-null="true"/> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> <one-to-one name="person" property-ref="address"/> </class>
create table Person ( personId bigint not null primary key, addressId bigint not null unique ) create table Address ( addressId bigint not null primary key )
Z主键兌的一对一兌需要用特定的id生成器?
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <one-to-one name="address"/> </class> <class name="Address"> <id name="id" column="personId"> <generator class="foreign"> <param name="property">person</param> </generator> </id> <one-to-one name="person" constrained="true"/> </class>
create table Person ( personId bigint not null primary key ) create table Address ( personId bigint not null primary key )
Zq接表的双向一对多兌。注?tt class=literal>inverse="true"可以出现在关联的L一端,即collection端或者join端?
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <set name="addresses" table="PersonAddress"> <key column="personId"/> <many-to-many column="addressId" unique="true" class="Address"/> </set> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> <join table="PersonAddress" inverse="true" optional="true"> <key column="addressId"/> <many-to-one name="person" column="personId" not-null="true"/> </join> </class>
create table Person ( personId bigint not null primary key ) create table PersonAddress ( personId bigint not null, addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )
Zq接表的双向一对一兌极ؓ|见Q但也是可行的?
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <join table="PersonAddress" optional="true"> <key column="personId" unique="true"/> <many-to-one name="address" column="addressId" not-null="true" unique="true"/> </join> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> <join table="PersonAddress" optional="true" inverse="true"> <key column="addressId" unique="true"/> <many-to-one name="address" column="personId" not-null="true" unique="true"/> </join> </class>
create table Person ( personId bigint not null primary key ) create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique ) create table Address ( addressId bigint not null primary key )
最后,q有 双向多对多关?/em>.
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <set name="addresses"> <key column="personId"/> <many-to-many column="addressId" class="Address"/> </set> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> <set name="people" inverse="true"> <key column="addressId"/> <many-to-many column="personId" class="Person"/> </set> </class>
create table Person ( personId bigint not null primary key ) create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) ) create table Address ( addressId bigint not null primary key )
Componentq个概念在Hibernate中几处不同的地方Z不同的目的被重复使用.
Component是一个被包含的对?它作为值类型被持久化,而非一个被引用的实体?#8220;component(lg)”q一术语指的是面向对象的合成概念Q而ƈ不是pȝ构架层次上的lg的概念)举个例子, 你可以对人(Person)如以下这h建模Q?
public class Person { private java.util.Date birthday; private Name name; private String key; public String getKey() { return key; } private void setKey(String key) { this.key=key; } public java.util.Date getBirthday() { return birthday; } public void setBirthday(java.util.Date birthday) { this.birthday = birthday; } public Name getName() { return name; } public void setName(Name name) { this.name = name; } ...... ...... }
public class Name { char initial; String first; String last; public String getFirst() { return first; } void setFirst(String first) { this.first = first; } public String getLast() { return last; } void setLast(String last) { this.last = last; } public char getInitial() { return initial; } void setInitial(char initial) { this.initial = initial; } }
现在,姓名(Name)是作?tt class=literal>?Person)的一个组成部分。需要注意的?需要对姓名 的持久化属性定义getter和setterҎ,但是不需要实CQ何的接口或申明标识符字段?
以下是这个例子的Hibernate映射文g:
<class name="eg.Person" table="person"> <id name="Key" column="pid" type="string"> <generator class="uuid.hex"/> </id> <property name="birthday" type="date"/> <component name="Name" class="eg.Name"> <!-- class attribute optional --> <property name="initial"/> <property name="first"/> <property name="last"/> </component> </class>
人员(Person)表中包?tt class=literal>pid, birthday, initial, first?last{字Dc?
像所有的值类型一? Component不支持共享引用?换句话说Q两个h可能重名Q但是两个person对象应该包含两个独立的name对象Q只不过是具?#8220;同样”的倹{?Component的gؓIZ语义学上来讲?span class=emphasis>专有?ad hoc)?每当 重新加蝲一个包含组件的对象,如果component的所有字DؓI,那么Hibernate假定整个component?I。对于绝大多数目?q样假定是没有问题的?
Component的属性可以是HibernatecdQ包括Collections, many-to-one 兌Q?以及其它Component {等Q。嵌套Component不应该作为特D的应用被考虑(Nested components should not be considered an exotic usage)?Hibernate向于支持设计细?fine-grained)的对象模型?
<component> 元素q允许有 <parent>子元?Q用来表明componentcM的一个属性返回包含它的实体的引用?
<class name="eg.Person" table="person"> <id name="Key" column="pid" type="string"> <generator class="uuid.hex"/> </id> <property name="birthday" type="date"/> <component name="Name" class="eg.Name" unique="true">> <parent name="namedPerson"/> <!-- reference back to the Person --> <property name="initial"/> <property name="first"/> <property name="last"/> </component> </class>
Hibernate支持component的集?例如: 一个元素是“姓名”q种cd的数l??你可以?tt class=literal><composite-element>标签替代<element>标签来定义你的component集合?
<set name="someNames" table="some_names" lazy="true"> <key column="id"/> <composite-element class="eg.Name"> <!-- class attribute required --> <property name="initial"/> <property name="first"/> <property name="last"/> </composite-element> </set>
注意Q如果你军_定义一个元素是联合元素?tt class=literal>SetQ正地实现equals()?tt class=literal>hashCode()是非帔R要的?
l合元素可以包含component但是不能包含集合。如果你的组合元素自w包含component, 必须使用<nested-composite-element>标签。这是一个相当特D的案例 - l合元素的集合自w可以包含component?q个时候你应该考虑一下用one-to-many兌是否会更恰当?试对这个组合元素重新徏模ؓ一个实体-但是需要注意的是,虽然Java模型和重新徏模前 是一LQ关pL型和持久性语义上仍然存在d的区别?
h意如果你使用<set>标签,一个组合元素的映射不支持可能ؓI的属? 当删除对象时, Hibernate必须使用每一个字D늚来确定一条记?在组合元素表中,没有单个的关键字D?, 如果有ؓnull的字D,q样做就不可能了。你必须作出一个选择Q要么在l合元素中用不能ؓI的属性, 要么选择使用<list>, <map>,<bag> 或?<idbag>而不?<set>?
l合元素有个特别的案例,是组合元素可以包含一?tt class=literal><many-to-one> 元素。类DL映射允许你映一个many-to-mang兌表作为组合元素额外的字段?A mapping like this allows you to map extra columns of a many-to-many association table to the composite element class.) 接下来的的例子是?tt class=literal>Order?tt class=literal>Item的一个多对多的关联关p??purchaseDate, price ?quantity ?tt class=literal>Item的关联属性?
<class name="eg.Order" .... > .... <set name="purchasedItems" table="purchase_items" lazy="true"> <key column="order_id"> <composite-element class="eg.Purchase"> <property name="purchaseDate"/> <property name="price"/> <property name="quantity"/> <many-to-one name="item" class="eg.Item"/> <!-- class attribute is optional --> </composite-element> </set> </class>
当然Q在另一斚wQ无法存在指向purchase的关联,因此不能实现双向兌查询。记住组建是值类型,q且不允许共享关联。单?tt class=literal>Purchase 可以攑֜包含Order的集合中Q但它不能同时被Item所兌?
即三重或多重管理都是可能的:
<class name="eg.Order" .... > .... <set name="purchasedItems" table="purchase_items" lazy="true"> <key column="order_id"> <composite-element class="eg.OrderLine"> <many-to-one name="purchaseDetails" class="eg.Purchase"/> <many-to-one name="item" class="eg.Item"/> </composite-element> </set> </class>
在查询中Q组合元素用的语法是和兌到其他实体的语法一L?
<composite-map-key>元素允许你映一个ComponentcM?tt class=literal>Map的keyQ?但是你必ȝ定你正确的在q个cM重写?tt class=literal>hashCode() ?equals()Ҏ?
你可以用一个component作ؓ一个实体类的标识符?你的componentcdL以下要求:
它必d?tt class=literal>java.io.Serializable接口
它必重新实?tt class=literal>equals()?tt class=literal>hashCode()Ҏ, 始终和组合关键字在数据库中的概念保持一?
注意Q在Hibernate3中,W二U要求ƈ非是Hibernate强制必须的。但最好这样做?/em>
你不能用一?tt class=literal>IdentifierGenerator产生l合关键字。作为替代应用程序必d配它自己的标识符?
使用<composite-id> 标签(q且内嵌<key-property>元素)代替通常?tt class=literal><id>标签?比如,OrderLinecd有一个依?tt class=literal>Order?联合)主键的主键?
<class name="OrderLine"> <composite-id name="id" class="OrderLineId"> <key-property name="lineId"/> <key-property name="orderId"/> <key-property name="customerId"/> </composite-id> <property name="name"/> <many-to-one name="order" class="Order" insert="false" update="false"> <column name="orderId"/> <column name="customerId"/> </many-to-one> .... </class>
现在QQ何关联到OrderLine 的外键都是复合的。在你的映射文g中,必须为其他类也这样声明。指?tt class=literal>OrderLine的关联可能被q样映射Q?
<many-to-one name="orderLine" class="OrderLine"> <!-- the "class" attribute is optional, as usual --> <column name="lineId"/> <column name="orderId"/> <column name="customerId"/> </many-to-one>
Q注意在各个地方<column>标签都是column属性的替代写法。)
指向OrderLine?tt class=literal>多对?/tt>兌也用联合外?
<set name="undeliveredOrderLines"> <key column name="warehouseId"/> <many-to-many class="OrderLine"> <column name="lineId"/> <column name="orderId"/> <column name="customerId"/> </many-to-many> </set>
?tt class=literal>Order? OrderLine的集合则是这?
<set name="orderLines" inverse="true"> <key> <column name="orderId"/> <column name="customerId"/> </key> <one-to-many class="OrderLine"/> </set>
(与通常一?<one-to-many>元素不声明Q何列.)
假若OrderLine本n拥有一个集?它也hl合外键?
<class name="OrderLine"> .... .... <list name="deliveryAttempts"> <key> <!-- a collection inherits the composite key type --> <column name="lineId"/> <column name="orderId"/> <column name="customerId"/> </key> <list-index column="attemptId" base="1"/> <composite-element class="DeliveryAttempt"> ... </composite-element> </set> </class>
你甚臛_以映?tt class=literal>Mapcd的属性:
<dynamic-component name="userAttributes"> <property name="foo" column="FOO"/> <property name="bar" column="BAR"/> <many-to-one name="baz" class="Baz" column="BAZ_ID"/> </dynamic-component>
?tt class=literal><dynamic-component>映射的语义上来讲Q它?tt class=literal><component>是相同的?q种映射cd的优点在于通过修改映射文gQ就可以h在部|时真实属性的能力.利用一个DOM解析器,是有可能在运行时L作映文件的?更好的是Q你可以通过Configuration对象来访问(或者修改)Hibernate的运行时元模型?
Hibernate支持三种基本的承映策略:
每个cd层结构一张表(table per class hierarchy)
每个子类一张表(table per subclass)
每个具体cM张表(table per concrete class)
此外QHibernateq支持第四种E有不同的多态映策略:
隐式多?implicit polymorphism)
对于同一个承层ơ内的不同分支,可以采用不同的映策略,然后用隐式多 态来完成跨越整个层次的多态。但是在同一?tt class=literal><class>根元?下,Hibernate不支持合了元素<subclass>?<joined-subclass>?tt class=literal><union-subclass> 的映。在同一?tt class=literal><class>元素下,可以混合使用 “每个cd层结构一张表”Qtable per hierarchyQ??#8220;每个子类一张表”Qtable per subclassQ?q两U映策略,q是通过l合元素<subclass>?<join>来实现的Q见后)?
假设我们有接?tt class=literal>Payment和它的几个实现类Q?CreditCardPayment, CashPayment, ?tt class=literal>ChequePayment。则“每个cd层结构一张表”(Table per class hierarchy)的映代码如下所C:
<class name="Payment" table="PAYMENT"> <id name="id" type="long" column="PAYMENT_ID"> <generator class="native"/> </id> <discriminator column="PAYMENT_TYPE" type="string"/> <property name="amount" column="AMOUNT"/> ... <subclass name="CreditCardPayment" discriminator-value="CREDIT"> <property name="creditCardType" column="CCTYPE"/> ... </subclass> <subclass name="CashPayment" discriminator-value="CASH"> ... </subclass> <subclass name="ChequePayment" discriminator-value="CHEQUE"> ... </subclass> </class>
采用q种{略只需要一张表卛_。它有一个很大的限制Q要求那些由子类定义的字D, ?tt class=literal>CCTYPEQ不能有非空(NOT NULL)U束?
对于上例中的几个c而言Q采?#8220;每个子类一张表”的映策略,代码如下所C:
<class name="Payment" table="PAYMENT"> <id name="id" type="long" column="PAYMENT_ID"> <generator class="native"/> </id> <property name="amount" column="AMOUNT"/> ... <joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT"> <key column="PAYMENT_ID"/> ... </joined-subclass> <joined-subclass name="CashPayment" table="CASH_PAYMENT"> <key column="PAYMENT_ID"/> <property name="creditCardType" column="CCTYPE"/> ... </joined-subclass> <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT"> <key column="PAYMENT_ID"/> ... </joined-subclass> </class>
需要四张表。三个子c表通过主键兌到超c表(因而关pL型实际上是一对一兌)?
注意Q对“每个子类一张表”的映策略,Hibernate的实C需要L别字D,而其?的对?关系映射工具使用了一U不同于Hibernate的实现方法,该方法要求在类 表中有一个类型L别字D?type discriminator column)。Hibernate采用的方法更 隑֮玎ͼ但从关系Q数据库Q这点上来看Q按理说它更正确。若你愿意用带有L别字 D늚“每个子类一张表”的策略,你可以结合?tt class=literal><subclass> ?tt class=literal><join>Q如下所C:
<class name="Payment" table="PAYMENT"> <id name="id" type="long" column="PAYMENT_ID"> <generator class="native"/> </id> <discriminator column="PAYMENT_TYPE" type="string"/> <property name="amount" column="AMOUNT"/> ... <subclass name="CreditCardPayment" discriminator-value="CREDIT"> <join table="CREDIT_PAYMENT"> <property name="creditCardType" column="CCTYPE"/> ... </join> </subclass> <subclass name="CashPayment" discriminator-value="CASH"> <join table="CASH_PAYMENT"> ... </join> </subclass> <subclass name="ChequePayment" discriminator-value="CHEQUE"> <join table="CHEQUE_PAYMENT" fetch="select"> ... </join> </subclass> </class>
可选的声明fetch="select"Q是用来告诉HibernateQ在查询类Ӟ 不要使用外部q接(outer join)来抓取子c?tt class=literal>ChequePayment的数据?
你甚臛_以采取如下方法和?#8220;每个cd层结构一张表”?#8220;每个子类一张表”q两U策略:
<class name="Payment" table="PAYMENT"> <id name="id" type="long" column="PAYMENT_ID"> <generator class="native"/> </id> <discriminator column="PAYMENT_TYPE" type="string"/> <property name="amount" column="AMOUNT"/> ... <subclass name="CreditCardPayment" discriminator-value="CREDIT"> <join table="CREDIT_PAYMENT"> <property name="creditCardType" column="CCTYPE"/> ... </join> </subclass> <subclass name="CashPayment" discriminator-value="CASH"> ... </subclass> <subclass name="ChequePayment" discriminator-value="CHEQUE"> ... </subclass> </class>
对上qCQ何一U映策略而言Q指向根c?tt class=literal>Payment?兌是?tt class=literal><many-to-one>q行映射的?
<many-to-one name="payment" column="PAYMENT_ID" class="Payment"/>
对于“每个具体cM张表”的映策略,可以采用两种Ҏ。第一U方法是使用 <union-subclass>?
<class name="Payment"> <id name="id" type="long" column="PAYMENT_ID"> <generator class="sequence"/> </id> <property name="amount" column="AMOUNT"/> ... <union-subclass name="CreditCardPayment" table="CREDIT_PAYMENT"> <property name="creditCardType" column="CCTYPE"/> ... </union-subclass> <union-subclass name="CashPayment" table="CASH_PAYMENT"> ... </union-subclass> <union-subclass name="ChequePayment" table="CHEQUE_PAYMENT"> ... </union-subclass> </class>
q里涉及三张表。每张表为对应类的所有属性(包括从超cȝ承的属性)定义相应字段?
q种方式的局限在于,如果一个属性在类中做了映,其字D名必须与所有子c?表中定义的相同?我们可能会在Hibernate的后l发布版本中攑֮此限制? 不允许在联合子类(union subclass)的承层ơ中使用标识生成器策?identity generator strategy), 实际? 主键的种?primary key seed)不得不ؓ同一l承层次中的全部被联合子cLq.
另一U可供选择的方法是采用隐式多态:
<class name="CreditCardPayment" table="CREDIT_PAYMENT"> <id name="id" type="long" column="CREDIT_PAYMENT_ID"> <generator class="native"/> </id> <property name="amount" column="CREDIT_AMOUNT"/> ... </class> <class name="CashPayment" table="CASH_PAYMENT"> <id name="id" type="long" column="CASH_PAYMENT_ID"> <generator class="native"/> </id> <property name="amount" column="CASH_AMOUNT"/> ... </class> <class name="ChequePayment" table="CHEQUE_PAYMENT"> <id name="id" type="long" column="CHEQUE_PAYMENT_ID"> <generator class="native"/> </id> <property name="amount" column="CHEQUE_AMOUNT"/> ... </class>
注意Q我们没有在M地方明确的提及接?tt class=literal>Payment。同时注?Payment的属性在每个子类中都q行了映。如果你想避免重复, 可以考虑使用XML实体(例如Q位?tt class=literal>DOCTYPE声明内的 [ <!ENTITY allproperties SYSTEM "allproperties.xml"> ] 和映中?tt class=literal>&allproperties;)?
q种Ҏ的缺陷在于,在Hibernate执行多态查询时(polymorphic queries)无法生成?UNION的SQL语句?
对于q种映射{略而言Q通常?tt class=literal><any>来实现到 Payment的多态关联映?
<any name="payment" meta-type="string" id-type="long"> <meta-value value="CREDIT" class="CreditCardPayment"/> <meta-value value="CASH" class="CashPayment"/> <meta-value value="CHEQUE" class="ChequePayment"/> <column name="PAYMENT_CLASS"/> <column name="PAYMENT_ID"/> </any>
对这一映射q有一炚w要注意。因为每个子c都在各自独立的元素<class> 中映?q且Payment只是一个接?Q每个子cd以很Ҏ的成为另一 个承体pM的一部分Q?你仍然可以对接口Payment使用多态查询?
<class name="CreditCardPayment" table="CREDIT_PAYMENT"> <id name="id" type="long" column="CREDIT_PAYMENT_ID"> <generator class="native"/> </id> <discriminator column="CREDIT_CARD" type="string"/> <property name="amount" column="CREDIT_AMOUNT"/> ... <subclass name="MasterCardPayment" discriminator-value="MDC"/> <subclass name="VisaPayment" discriminator-value="VISA"/> </class> <class name="NonelectronicTransaction" table="NONELECTRONIC_TXN"> <id name="id" type="long" column="TXN_ID"> <generator class="native"/> </id> ... <joined-subclass name="CashPayment" table="CASH_PAYMENT"> <key column="PAYMENT_ID"/> <property name="amount" column="CASH_AMOUNT"/> ... </joined-subclass> <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT"> <key column="PAYMENT_ID"/> <property name="amount" column="CHEQUE_AMOUNT"/> ... </joined-subclass> </class>
我们q是没有明确的提?tt class=literal>Payment?如果我们针对接口Payment执行查询 ——如from Payment—?Hibernate 自动q回CreditCardPayment(和它的子c,因ؓ 它们也实C接口Payment)?CashPayment?tt class=literal>Chequepayment的实例, 但不q回NonelectronicTransaction的实例?
?#8220;每个具体cL一张表”Qtable per concrete-classQ的映射{略而言Q隐式多态的 方式有一定的限制。?tt class=literal><union-subclass>映射的限制则没有?么严根{?
下面表格中列Z在Hibernte?#8220;每个具体cM张表”的策略和隐式多态的限制?
?nbsp;10.1. l承映射Ҏ?Features of inheritance mappings)
l承{略(Inheritance strategy) | 多态多对一 | 多态一对一 | 多态一对多 | 多态多对多 | 多?load()/get() | 多态查?/th> | 多态连?join) | 外连?Outer join)抓取 |
---|---|---|---|---|---|---|---|---|
每个cd层结构一张表 | <many-to-one> | <one-to-one> | <one-to-many> | <many-to-many> | s.get(Payment.class, id) | from Payment p | from Order o join o.payment p | 支持 |
每个子类一张表 | <many-to-one> | <one-to-one> | <one-to-many> | <many-to-many> | s.get(Payment.class, id) | from Payment p | from Order o join o.payment p | 支持 |
每个具体cM张表(union-subclass) | <many-to-one> | <one-to-one> | <one-to-many> (仅对?tt class=literal>inverse="true"的情? | <many-to-many> | s.get(Payment.class, id) | from Payment p | from Order o join o.payment p | 支持 |
每个具体cM张表(隐式多? | <any> | 不支?/em> | 不支?/em> | <many-to-any> | s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult() | from Payment p | 不支?/em> | 不支?/em> |
Criteria criteria = session.createCriteria(User.class);
1)criteria.add(Restrictions.gt("age", new Integer(20)));
2)criteria.add(Restrictions.lt("age", new Integer(40)));
3)criteria.add(Restrictions.or(Restrictions.eq("age", new Integer(20)), Restrictions.isNull("age")));
crit.add(Restrictions.ilike(
"name"
,
"1"
, MatchMode.END));
//
// ilike?/span>i?/span>ignore之意,所?/span>q?/span>?/span>查询?/span>englishName"Optima?XL?100K?Ultracentrifuge"Q忽略大写Q的记录
4)criteria.add(Restrictions.sqlRestriction("{alias}.name LIKE (?)", "cater%", Hibernate.STRING));
5) Integer[] ages = {new Integer(20), new Integer(40)};
Type[] types = {Hibernate.INTEGER, Hibernate.INTEGER};
criteria.add(Restrictions.sqlRestriction("{alias}.age BETWEEN (?) AND (?)", ages, types));
6) criteria.setFirstResult(51);
criteria.setMaxResult(50);
7) l计?/span>rowCount()?/span>count()?/span>max()?/span>min()?/span>countDistinct()
criteria.setProjection(Projections.avg("age"));
8)分组20,20,25,30 à 20.25.30
criteria.setProjection(Projections.groupProperty("age"));
9)l合l计分组
ProjectionList projectionList = Projections.projectionList();
projectionList.add(Projections.groupProperty("age"));
projectionList.add(Projections.rowCount());
Criteria criteria = session.createCriteria(User.class);
criteria.setProjection(projectionList);
10) Query Criteria Id: data type Long
projectionList.add(crit.add( Expression.idEq(
11111L
) );
11) Query Criteria Id: Not Equal
crit.add( Expression.ne(
"name"
,
"noName"
) );
)
12)
crit.setProjection(Projections.rowCount());
13
Q?/span>
q?/span>
?/span>
?/span>
CZ?/span>
复记?/span>
criteria.setResultTransformer(criteria.DISTINCT_ROOT_ENTITY);
List users = criteria.list();
Restrictions的幾個常用限?/span>?/span>詢方法如下表所C:
Ҏ |
?/span>?/span> |
Restrictions.eq |
{於 |
Restrictions.allEq |
使用MapQ?/span>key/value進行多個等於的比對 |
Restrictions.gt |
大於 > |
Restrictions.ge |
大於{於 >= |
Restrictions.lt |
於 < |
Restrictions.le |
於{於 <= |
Restrictions.between |
應SQL?/span>BETWEEN子句 |
Restrictions.like |
應SQL?/span>LIKE子句 |
Restrictions.in |
應SQL?/span>in子句 |
Restrictions.and |
and關係 |
Restrictions.or |
or關係 |
Restrictions.sqlRestriction |
SQL限定?/span>?/span> |
HQLQ?/span>Hibernate Query LanguageQ?/span>
PS:
1:HOL是不区分大小写的,但名U是区分大小写的.
2:如果User別提供有適當的建構ҎQ則可以在?/span>HQL時直接指定新Z個物件傳?/span>
Query query = session.createQuery("select new User(user.name, user.age) from User as user");
3. 如果試圖使用Session?/span>saveOrupdate()ҎQ則會新增一{資料而不是更新原有的資料?/span>
4. 還可以結?/span>having子句Q例如只^均大?/span>20的資料分i顯C出來:
Query query = session.createQuery("select user.sex, avg(user.age) from User user group by user.sex having avg(user.age) > 20");
5. 更新与删除的时?/span>
Session session = sessionFactory.openSession();
Transaction tx= session.beginTransaction();
Query query = session.createQuery("update User set name='momor' where name='bbb'");
query.executeUpdate();
tx.commit();
session.close();
Hibernate:HQL/QBC查询?/span>a?/span>?/span>的用?/span>
Hib?/span>索方?/span>
1'?/span>?/span>?/span>?/span>图检索方式。?/span>q?/span>?/span>l?/span>?/span>?/span>?/span>?/span>象,?/span>?/span>.iterator()Ҏ可以得到order?/span>?/span>
如果是首?/span>?/span>行此ҎQ?/span>Hib会从数据?/span>?/span>载关?/span>?/span>order?/span>象,?/span>?/span>׃~?/span>存中得到?/span>
2'OID索方式。?/span>q?/span>session?/span>getQ?/span>loadҎ知道?/span>OID的情况下可以使用
3'HQL索方式。用面?/span>?/span>象的HQL查询?/span>?/span>session?/span>findҎ利用HQL?/span>查询
4'QBC索方式?/span>利用QBCAPI?/span>索它是封装了Z字符串的查询?/span>?/span>
5'本地?/span>SQL索方式。用本地数?/span>?/span>?/span>SQL查询?/span>?/span>Hib?/span>负责?/span>索到?/span>JDBCl?/span>果集映射?/span>持久?/span>?/span>?/span>?/span>?/span>
?/span>U检索方式的使用?/span>合和特点Q?/span>
HQL Q?/span> 是面?/span>?/span>象的查询?/span>aQ同SQL有些怼?/span>Hib中最常用的方式?/span>
查询?/span>定各U查?/span>条g?/span>
支持投媄查询Q?/span>索出?/span>象的部分属性?/span>
支持?/span>|?/span>Q允?/span>使用having?/span>group by
提供内制的聚集函敎ͼsum()Q?/span>min()Q?/span>max()
?/span>?/span>用用?/span>的自?/span>?/span>SQL
支持?/span>查询Q嵌入式查询
支持动态绑定参?/span>
?/span>?/span>使用Query接口?/span>?/span>session?/span>findҎ?/span>
Query Q = session.createQuery("from customer as c where c.name = :customerName" + "and c.age = :customerAge");
query.setString ("customerName" , "tom");
query.setInteger("customerAge" , "21");
list result = query.list();
QBC : QBCAPI提供了另一U?/span>方式Q主要是Criteria接口?/span>Criterion接口?/span>Expressionc?/span>
Criteria criteria = session.createCriteria(customer.class);
Criterion criterion1 = Expression.like("name","t%");
Criterion criterion2 = Expression.eq("age",new Integer(21));
Critera = criteria.add(criterion1) ;
Critera = criteria.add(criterion2) ;
list result = criteria.list();
或是Q?/span> list result = session.createCriteria(Customer.class).add(Expression.eq("this.name","tom")).list();
SQL : 采用HQL?/span>QBC?/span>?/span>Q?/span>Hib生成SQL?/span>句适用所有数?/span>?/span>?/span>
Query query = session.createSQLQuery("select {c.*} from customers c where c.name like : customername " + "and c.age = :customerage","c",customer.calss);
query.setString("customername","tom");
query.setInteger("customerage","21");
list result = query.list();
/////////////?/span>态查?/span>
HQL Q?/span>session.createQuery("from employee");
QBC Q?/span>session.createCriteria(employee.class);
HQL : session.createQuery("from hourlyEmployee");
QBC : session.createCriteria(hourlyEmployee.class);
下面?/span>HQL查询?/span>句将索出所有的持久?/span>?/span>象:
from java.lang.Object ;
from java.io.serializable ;
////////////查询的排?/span>
1'查询l?/span>果按照客?/span>姓名升序排列Q?/span>
HQL Q?/span>
Query query = session.createQuery ("from customer c order by c.name");
QBC Q?/span>
Criteria criteria = session.createCriteria(customer.class);
criteria.addOrder(order.asc("name"));
HQL :
Query query = session.createQuery ("from customer c order by c.name asc , c.age desc");
QBC :
Criteria criteria = session.createCriteria(customer.class);
criteria.addOrder(order.asc ("name"));
criteria.addOrder(order.desc("age"));
import net.sf.hibernate.pression.Order
import mypack.Order
...........
Criteria criteria = session.createCritria (mypack.Order.class);
criteria.addOrder(net.sf.hibernate.Order.asc("name"));
///////////HQL?/span>句的参数l?/span>?/span>Query接口提供?/span>l?/span>定各U?/span>Hib映射c?/span>型的Ҏ?/span>
setBinary()
setString()
setBoolean()
setByte()
setCalendar()
setCharacter()
setDate()
setDouble()
setText()
setTime()
setTimestamp()
setEntity()//把参C一个持久化c?/span>的事?/span>l?/span>?/span>lsit result = session.createQuery("from order o where o.customer = :customer").setEntity("customer" , customer).list ;
setParameter()//l?/span>定Q?/span>c?/span>型的参数
setProperties()//把命名参C一?/span>?/span>象的属?/span>值绑?/span> Query query = session.createQuery("from customer c where c.name =: name " + "and c.age =:age" );
Query.setProperties(customer);
多对一情况
DetachedCriteria zlbdc=DetachedCriteria.forClass(ZlZlxm.class, "zlb");
// .createAlias("zlb.zl", "t")
// .setProjection(Property.forName("t.id").count())
//.add(Property.forName("t.id").eq(new Long(1)))
org.hibernate.criterion.Projection projection=org.hibernate.criterion.Projections.projectionList()
.add(org.hibernate.criterion.Property.forName("zlb.fdxx"),"id");
zlbdc.setProjection(projection);
//zlbdc.createCriteria("zl");//加上q句是内联接(inner join)zl为集?br>投媄查询Q得C是object[]
DetachedCriteria zlbdc=DetachedCriteria.forClass(ZlZlxm.class, "zlb")
//zlbdc.createCriteria("zl"); //此处为对?br> .createAlias("zlb.zl", "t") //别名
.setProjection(Property.forName("t.id").count())
.add(Property.forName("t.id").eq(new Long(1))); //q里l计的是个数内联?inner join)
//zladc.setFetchMode("zla.zlZlxm", org.hibernate.FetchMode.JOIN);//无作?集合lazy)Q?Q,如果not lazy会是全部查?/p>
Criteria Query通过面向对象化的设计Q将数据查询条g装Z个对象。简单来
ԌCriteria Query可以看作是传l?/span>SQL的对象化表示Q如Q?span>
Criteria criteria = session.createCriteria(User.class);
criteria.add(Expression.eq("name","Erica"));
criteria.add(Expression.eq("sex",new Integer(1)));
q里?/span>criteria 实例实际上是SQL “Select * from t_user where
name=’Erica’ and sex=
以观?/span>Hibernate在运行期生成?/span>SQL语句Q?span>
Hibernate 在运行期会根?/span>Criteria 中指定的查询条gQ也是上面代码中通过
criteria.addҎd的查询表辑ּQ生成相应的SQL语句?span>
q种方式的特Ҏ比较W合Java E序员的~码习惯Qƈ且具备清晰的可读性。正?span>
为此Q不?/span>ORM实现中都提供了类似的实现机制Q如Apache OJBQ?span>
对于Hibernate的初学者,特别是对SQL了解有限的程序员而言Q?/span>Criteria Query
无疑是上手的极佳途径Q相?/span>HQLQ?/span>Criteria Query提供了更易于理解的查询手D,?span>
?/span>IDE?/span>Coding Assist机制Q?/span>Criteria的用几乎不用太多的学习?span>
Criteria 查询表达?span>
Criteria 本n只是一个查询容器,具体的查询条仉要通过Criteria.add
Ҏd?/span>Criteria实例中?span>
如前例所C,Expression 对象具体描述了查询条件。针?/span>SQL 语法Q?span>
Expression提供了对应的查询限定机制Q包括:
Ҏ 描述
Expression.eq 对应SQL“field = value”表达式?span>
?/span>Expression.eq("name","Erica")
Expression.allEq 参数Z?/span>Map对象Q其中包含了多个属性-值对
应关pR相当于多个Expression.eq关系的叠加?span>
Expression.gt 对应SQL中的 “field > value ” 表达?span>
Hibernate Developer’s Guide Version 1.0
September 2, 2004 So many open source projects. Why not Open your Documents?
Expression.ge 对应SQL中的 “field >= value” 表达?span>
Expression.lt 对应SQL中的 “field < value” 表达?span>
Expression.le 对应SQL中的 “field <= value” 表达?span>
Expression.between 对应SQL中的 “between” 表达?span>
如下面的表达式表C年龄(ageQ位?/span>13?/span>50?span>
间内?span>
Expression.between("age",new
Integer(13),new Integer(50));
表达?span>
Expression.in 对应SQL中的 ”field in …” 表达?span>
Expression.eqProperty 用于比较两个属性之间的|对应SQL中的“field
= field”?span>
如:
Expression.eqProperty(
"TUser.groupID",
"TGroup.id"
);
Expression.gtProperty 用于比较两个属性之间的|对应SQL中的“field
> field”?span>
Expression.geProperty 用于比较两个属性之间的|对应SQL中的“field
>= field”?span>
Expression.ltProperty 用于比较两个属性之间的|对应SQL中的“field
< field”?span>
Expression.leProperty 用于比较两个属性之间的|对应SQL中的“field
<= field”?span>
Expression.and and关系l合?span>
如:
Expression.and(
Expression.eq("name","Erica"),
Expression.eq(
"sex",
new Integer(1)
)
);
Expression.or or关系l合?span>
如:
Hibernate Developer’s Guide Version 1.0
September 2, 2004 So many open source projects. Why not Open your Documents?
Expression.or(
Expression.eq("name","Erica"),
Expression.eq("name","Emma")
);
Expression.sql 作ؓ补充Q本Ҏ提供了原?/span>SQL语法的支持。我
们可以通过q个Ҏ直接通过SQL语句限定查询
条g?span>
下面的代码返回所有名UC“Erica”起始的记录:
Expression.sql(
“lower({alias}.name) like lower(?)”,
"Erica%",
Hibernate.STRING
);
其中?#8220;{alias}”由Hibernate在运行期?span>
用当前关联的POJO别名替换?span>
注意Expression 各方法中的属性名参数Q如Express.eq中的W一个参敎ͼQ这?span>
所谓属性名?/span>POJO中对应实际库表字D늚属性名Q大写敏感Q,而非库表中的?span>
际字D名U?span>
Criteria 高Ҏ?span>
限定q回的记录范?span>
通过criteria. setFirstResult/setMaxResults Ҏ可以限制一ơ查询返?span>
的记录范?/span>:
Criteria criteria = session.createCriteria(TUser.class);
//限定查询q回索结果中Q从W一百条l果开始的20条记?span>
criteria.setFirstResult(100);
criteria.setMaxResults(20);
Ҏ询结果进行排?span>
//查询所?/span>groupId=2的记?span>
//q分别按照姓?/span>(序)?/span>groupIdQ逆序Q排?span>
Criteria criteria = session.createCriteria(TUser.class);
criteria.add(Expression.eq("groupId",new Integer(2)));
criteria.addOrder(Order.asc("name"));
Hibernate Developer’s Guide Version 1.0
September 2, 2004 So many open source projects. Why not Open your Documents?
criteria.addOrder(Order.desc("groupId"));
Criteria作ؓ一U对象化的查询封装模式,不过׃Hibernate在实现过E中精?span>
更加集中?/span>HQL查询语言上,因此Criteria的功能实现还没做到尽善尽(q点上,OJB
?/span>Criteria 实现倒是值得借鉴Q,因此Q在实际开发中Q徏议还是采?/span>Hibernate ?span>
Ҏ荐的查询装模式Q?/span>HQL?/span>
如图 1 ?hibernate 设计?criteriaspecification 作ؓ criteria 的顶U接口,其下面提供了 criteria ?detachedcriteria ?
criteria ?detachedcriteria 的主要区别在于创建的形式不一P criteria ?a id=vad_8 onmouseover="if(typeof(showTitle)!='undefined'){this.title='';window.clearTimeout(hideTO);showTitle(event, this, 8,'');}" title="光于华夏2 @Vogate.com" onclick="" onmouseout="if(typeof(showTitle)!='undefined'){mouseIsOverLayer = false; mouseOverWhileLoad = false; hideTO = window.setTimeout('checkIfMouseOverLayer()',500);}" target=_blank>在线的,所以它是由 hibernate session q行创徏的;?detachedcriteria 是离U的Q创建时无需 session Q?detachedcriteria 提供?4 个静态方?forclass(class) ?forentityname(name) q行 detachedcriteria 实例的创建?spring 的框架提供了
gethibernatetemplate().findbycriteria(detachedcriteria) Ҏ可以很方便地Ҏ
detachedcriteria 来返回查询结果?
如图 1 Q?criteria ?detachedcriteria 均可使用 criterion ?projection 讄查询条g。可以设|?fetchmode( 联合查询抓取的模?) Q设|排序方式。对?criteria q可以设|?flushmodel Q冲?session 的方式)?lockmode Q数据库锁模式)?
下面对 criterion ?projection q行详细说明?
?1
criterion ?criteria 的查询条件?
criteria 提供?add(criterion criterion) Ҏ来添加查询条件。图 2 ?criterion 的结构图?criterion 接口的主?a id=vad_9 onmouseover="if(typeof(showTitle)!='undefined'){this.title='';window.clearTimeout(hideTO);showTitle(event, this, 9,'');}" title="" onclick="" onmouseout="if(typeof(showTitle)!='undefined'){mouseIsOverLayer = false; mouseOverWhileLoad = false; hideTO = window.setTimeout('checkIfMouseOverLayer()',500);}" target=_blank>实现包括Q?example ?junction ?simpleexpression 。?junction 的实际用是它的两个子类 conjunction ?disjunction Q分别是使用 and ?or 操作W进行来联结查询条g集合?
criterion 的实例可以通过 restrictions 工具cL创徏Q?restrictions 提供了大量的静态方法,?eq Q等于)?ge Q大于等于)?between {来Ҏ的创?criterion 查询条g
Q?simpleexpression 实例Q。除此之外, restrictions q提供了Ҏ来创?conjunction ?disjunction 实例Q通过往该实例的 add(criteria) Ҏ来增加查询条件Ş成一个查询条仉合?
至于 example 的创建有所不同Q?example 本n提供了一个静态方?create(object entity) Q即Ҏ一个对象(实际使用中一般是映射到数据库的对象)来创建。然后可以设|一些过滤条Ӟ
example exampleuser =example.create(u)
.ignorecase() // 忽略大小?
.enablelike(matchmode.anywhere);
// ?string cd的属性,无论在那里值在那里都匹配。相当于 %value%
?2
project 主要是让 criteria 能够q行报表查询Qƈ可以实现分组?project 主要?simpleprojection ?projectionlist ?property 三个实现。其?simpleprojection ?projectionlist 的实例化是由内徏?projections 来完成,如提供的 avg ?count ?max ?min ?sum 可以让开发者很ҎҎ个字D进行统计查询?
property 是对某个字段q行查询条g的设|,如通过
porperty.forname(“color”).in(new string[]{“black”,”red”,”write”}); 则可以创Z?project 实例。通过 criteria ?add(project) Ҏ加入到查询条件中厅R?
?3
使用 criteria q行查询Q主要要清晰的是 hibernate 提供了那些类和方法来满开发中查询条g的创建和l装Q其l构层次如何。这样用v来便可得心应手?
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Department.class); detachedCriteria.add(Restrictions.eq("name", "department")).createAlias("employees", "e").add(Restrictions.gt(("e.age"), new Integer(20))); |
detachedCriteria.getExecutableCriteria(session).list(); |
HibernateTemplate.execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { .... } } |
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Department.class); detachedCriteria.createAlias("employees", "e").add(Restrictions.eq("name", "department")).add(Restrictions.gt(("e.age"), new Integer(20))); departmentManager.findByCriteria(detachedCriteria); |
public List findByCriteria(final DetachedCriteria detachedCriteria) { return (List) getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { Criteria criteria = detachedCriteria.getExecutableCriteria(session); return criteria.list(); } }); } |
Criteria criteria = detachedCriteria.getExecutableCriteria(session); return criteria.list(); |
private boolean exposeNativeSession = false; ... |
Session sessionToExpose = (exposeNativeSession ? session : createSessionProxy(session)); |
public Criteria getExecutableCriteria(Session session) { impl.setSession( (SessionImpl) session ); // 要求SessionImplQSpring传递的是Proxy return impl; } |
public List findByCriteria(final DetachedCriteria detachedCriteria) { return (List) getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException { Criteria criteria = detachedCriteria.getExecutableCriteria(session); return criteria.list(); } }, true); } |
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
/**
* Configures and provides access to Hibernate sessions, tied to the
* current thread of execution. Follows the Thread Local Session
* pattern, see {@linkhttp://hibernate.org/42.html}.
*/
public class HibernateSessionFactory{
/**
* Location of hibernate.cfg.xml file.
* NOTICE: Location should be on the classpath as Hibernate uses
* #resourceAsStream style lookup for its configuration file. That
* is place the config file in a Java package - the default location
* is the default Java package.<br><br>
* Examples: <br>
* <code>CONFIG_FILE_LOCATION = "/hibernate.conf.xml".
* CONFIG_FILE_LOCATION = "/com/foo/bar/myhiberstuff.conf.xml".</code>
*/
private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
/** Holds a single instance of Session */
private static final ThreadLocal threadLocal = new ThreadLocal();
/** The single instance of hibernate configuration */
private static final Configuration cfg = new Configuration();
/** The single instance of hibernate SessionFactory */
private static org.hibernate.SessionFactory sessionFactory;
/**
* Returns the ThreadLocal Session instance. Lazy initialize
* the <code>SessionFactory</code> if needed.
*
* @return Session
* @throws HibernateException
*/
public static Session currentSession() throws HibernateException {
Session session = (Session) threadLocal.get();
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
try {
cfg.configure(CONFIG_FILE_LOCATION);
sessionFactory = cfg.buildSessionFactory();
} catch (Exception e) {
System.err
.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
session = (sessionFactory != null) ? sessionFactory.openSession()
: null;
threadLocal.set(session);
}
return session;
}
/**
* Close the single hibernate session instance.
*
* @throws HibernateException
*/
public static void closeSession() throws HibernateException {
Session session = (Session) threadLocal.get();
threadLocal.set(null);
if (session != null) {
session.close();
}
}
/**
* Default constructor.
*/
private HibernateSession() {
}
} <!-- Generated by MyEclipse Hibernate Tools. --> <session-factory> </session-factory> </hibernate-configuration> /** public class Employee implements java.io.Serializable {
/**
/** default constructor */ /** minimal constructor */ public Integer getId() { public String getName() { import java.util.ArrayList; import org.hibernate.Session; import com.semovy.framework.base.HibernateSession; <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
(3).自动在classes下生hibernate.cfg.xml配置文g
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"
<hibernate-configuration>
<property name="connection.username">root</property>
<property name="connection.url">jdbc:mysql://localhost:3306/test?useUnicode=true;characterEncoding=gbk</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="myeclipse.connection.profile">MySqlDB</property>
<property name="connection.password">1234</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<mapping resource="com/semovy/business/pojo/Employee.hbm.xml" /><!--对应对象映射文g资源-->.
三、打开MyEclipse的DB Browser选择Employee叛_creating hibernate mapping,讄持久c\径好之后?br />便自动生Employee持久c,与同一目录下的Employee.hbm.xml两个文g
1).
package com.semovy.business.pojo;
* Employee generated by MyEclipse - Hibernate Tools
*/
// Fields
*
*/
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
// Constructors
public Employee() {
}
public Employee(Integer id) {
this.id = id;
}
/** full constructor */
public Employee(Integer id, String name) {
this.id = id;
this.name = name;
}
// Property accessors
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
2).Employee.hbm.xml文g
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"<!--
Mapping file autogenerated by MyEclipse - Hibernate Tools
-->
<hibernate-mapping>
<class name="com.semovy.business.pojo.Employee" table="employee" ><!---一定弃掉catalog属性,我是卡在q里好久Q运行有异常-->
<id name="id" type="integer">
<column name="id" />
<generator class="identity" />
</id>
<property name="name" type="string">
<column name="name" length="50" />
</property>
</class>
</hibernate-mapping>
四,建立Employee持久化类的业务逻辑Q?br />package com.semovy.business.service;
import java.util.List;
import org.hibernate.Transaction;
/**
* this class supply all type of busniss service method for Employees
* @author Semovy
* @since 2006-11-08
* @version 1.0
*/
public class EmployeeService {
Session session = null;
public EmployeeService(){}
public List findAllEmployees()
{
List employees = new ArrayList();
try
{
session = HibernateSession.currentSession();
Transaction tx = session.beginTransaction();
employees = session.createQuery("from Employee").list();
tx.commit();
return employees;
}
catch(Exception ex)
{
ex.printStackTrace();
return null;
}
finally
{
HibernateSession.closeSession();
}
}
}
五,建立jsp面listEmployees.jsp来调用测试hibernate.
<%@ page language="java" import="java.util.*,
com.semovy.business.pojo.Employee,com.semovy.business.service.EmployeeService"
pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'listEmployees.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
This is my JSP page.<br>
<%
EmployeeService es = new EmployeeService();
List l = es.findAllEmployees();
if(l != null)
{
Iterator it = l.iterator();
while(it.hasNext())
{
Employee em = (Employee)it.next();
out.print("ID: " + em.getId() + "Name: " + em.getName()+"<br>");
}
}
%>
</body>
</html>
六、发布应?/p>