HQL相关知识

4.3  使用HQL查询

Hibernate提供了异常大的查询体系,使用Hibernate有多种查询方式。可以选择使用HibernateHQL查询,或者使用条件查询,甚至可以使用原生的SQL查询语句,此外提供了一数据过滤功能,些都可用于筛选数据。

下面分Hibernate4数据筛选方法:

4.3.1  HQL查询

HQLHibernate Query Language写,HQL法很像SQL法,但HQL是一面向象的查询语言。因此,SQL的操作象是数据表和列等数据象,而HQL的操作象是例、属性等。

HQL是完全面向象的查询语言,因此可以支持承和多等特征。

HQL查询QueryQuery对应一个查询对象。使用HQL查询可按如下步骤进行:

1Hibernate Session象;

2HQL句;

3)以HQL句作参数,SessioncreateQuery方法查询对象;

4)如果HQL句包含参数,QuerysetXxx方法参数赋值

5Query象的list等方法遍历查询结果。

看下面的查询示例:

public class HqlQuery

{

    public static void main(String[] args)throws Exception

    {

        HqlQuery mgr = new HqlQuery();

        //查询方法

        mgr.findPersons();

        //第二个查询方法

        mgr.findPersonsByHappenDate();

        HibernateUtil.sessionFactory.close();

    }

    //第一个查询方法

    private void findPersons()

    {

        //Hibernate Session

        Session sess = HibernateUtil.currentSession();

        //始事

        Transaction tx = sess.beginTransaction();

        //HQLQuery.

        //setString方法HQL句的参数赋值

        //Querylist方法访问查询的全部

        List pl = sess.createQuery("from Person p where p.myEvents.title

        = :eventTitle")

                        .setString("eventTitle","很普通事情")

                        .list();

        //历查询的全部

        for (Iterator pit = pl.iterator() ; pit.hasNext(); )

        {

            Person p = ( Person )pit.next();

            System.out.println(p.getName());

        }

        //提交事

        tx.commit();

        HibernateUtil.closeSession();

    }

    //第二个查询方法

    private void findPersonsByHappenDate()throws Exception

    {

        //Hibernate Session

        Session sess = HibernateUtil.currentSession();

        Transaction tx = sess.beginTransaction();

        //解析出Date

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        Date start = sdf.parse("2005-01-01");

        System.out.println("统开始通日期找人" + start);

        //SessioncreateQuery方法Query

        //置参数

        //返回果集

        List pl = sess.createQuery(

            "from Person p where p.myEvents.happenDate between :firstDate

            and :endDate")

                        .setDate("firstDate",start)

                        .setDate("endDate",new Date())

                        .list();

        //历结果集

        for (Iterator pit = pl.iterator() ; pit.hasNext(); )

        {

            Person p = ( Person )pit.next();

            System.out.println(p.getName());

        }

        tx.commit();

        HibernateUtil.closeSession();

    }

}

上面的示例程序,可看出查询步骤基本相似。Query象可以连续多次置参数,得益于Hibernate Query设计

通常,setXxx方法的返回都是void,但Hibernate QuerysetXxx方法返回Query本身。因此,程序通SessionQuery后,直接多次setXxx方法HQL句的参数赋值,再直接list方法返回查询到的全部果即可。

Query包含两个方法:

  ● setFirstResultint firstResult),置返回的果集从第几条记录开始。

  ● setMaxResultsint maxResults),置本次查询返回的果数。

两个方法用于实现Hibernate

下面简单HQL句的法。

HQL句本身是不区分大小写的。也就是HQL句的关键字和函数都是不区分大小写的。但HQL句中所使用的包名、名、例名和属性名都区分大小写。

4.3.2  HQL查询from子句

from子句是最简单HQL句,也是最基本的HQL句。from关键字后跟持久化名。例如:

from Person

表明从Person持久化出全部的例。

大部分候,推荐为该Person例起名。例如:

from Person as p

在上面的HQL句中,Person持久化中的例的p,既然 p例名,因此也应该遵守Java的命名规则:第一个单词的首字母小写,后面单词的首字母大写。

命名as关键字是可的,但了增加可性,建保留。

from可同多个持久化,此生一个笛卡儿或跨表的接。

4.3.3  HQL查询select子句

select子句用于确定选择出的属性,当然select选择的属性必from后持久化包含的属性。例如:

select p.name from Person as p

select可以选择任意属性,不可以选择持久化的直接属性,可以选择组件属性包含的属性,例如:

select p.name.firstName from Person as p

select也支持将选择出的属性存入一个List象中,例如:

select new list(p.name , p.address) from Person as p

甚至可以将选择出的属性直接封装成象,例如:

select new ClassTest(p.name , p.address) from Person as p

前提是ClassTest支持p.namep.address的构造器,假如p.name的数据型是           Stringp.address的数据型是StringClassTest有如下的构造器:

ClassTest(String s1, String s2)

select支持给选中的表达式命名名,例如:

select p.name as personName from Person as p

这种用法与new map合使用更普遍。如:

select new map(p.name as personName) from Person as p

这种情形下,选择出的是Map构,以personNamekey实际选出的value

4.3.4  HQL查询的聚集函数

HQL也支持在出的属性上,使用聚集函数。HQL支持的聚集函数与SQL完全相同,有如下5个:

  ● avg算属性平均

  ● count统计选择对象的数量。

  ● max统计属性的最大

  ● min统计属性的最小

  ● sum算属性和。

例如:

select count(*) from Person

select max(p.age) from Person as p

select子句支持字符串接符、算运算符以及SQL函数。如:

select p.name ||  ""  ||  p.address from Person as p

select子句也支持使用distinctall关键字,此的效果与SQL中的效果完全相同。

4.3.5  态查询

HQL句被设计成能理解多态查询from后跟的持久化名,不查询持久化的全部例,查询该类的子的全部例。

如下面的查询语句:

from Person as p

该查询语句不查询Person的全部例,查询Person的子,如Teacher的全部例,前提是PersonTeacher完成了正确的承映射。

HQL支持在from子句中指定任何Java或接口,查询会返回承了该类的持久化子例或返回实现该接口的持久化例。下面的查询语句返回所有被持久化的象:

from java.lang.Object o

如果Named接口有多个持久化,下面的句将返回些持久化的全部例:

from Named as n

注意:后面的两个查询将需要多个SQL SELECT句,因此无法使用order by子句对结果集行排序,从而,不允许对这查询结果使用Query.scroll()方法。

4.3.6  HQL查询where子句

where子句用于筛选选中的果,选择的范。如果没有持久化例命名名,可以直接使用属性名引用属性。

如下面的HQL句:

from Person where name like 'tom%'

上面HQL句与下面的句效果相同:

from Person as p where p.name like "tom%"

在后面的HQL句中,如果持久化例命名了名,则应该使用完整的属性名。两个HQL句都可返回name属性以tom开头例。

合属性表达式加where子句的功能,例如如下HQL句:

from Cat cat where cat.mate.name like "kit%"

该查询将被翻一个含有内接的SQL查询,翻后的SQL句如下:

select * from cat_table as table1 cat_table as table2 where table1.mate =

table2.id and table1.name like "kit%"

再看下面的HQL查询语句:

from Foo foo where foo.bar.baz.customer.address.city like"guangzhou%"

SQL查询语句,将成一个四表接的查询

=运算符不可以被用来比属性的,也可以用来比较实例:

from Cat cat, Cat rival where cat.mate = rival.mate

select cat, mate

from Cat cat, Cat mate

where cat.mate = mate

特殊属性(小写)id可以用来表示一个象的标识符。(也可以使用该对象的属性名。)

from Cat as cat where cat.id = 123

from Cat as cat where cat.mate.id = 69

第二个查询是一个内查询,但在HQL查询语句下,无体会多表接,而完全使用面向象方式的查询

id也可代表引用标识符。例如,Person有一个引用标识符,它由country属性 与medicareNumber两个属性成。

下面的HQL句有效:

from Person as person

where person.id.country = 'AU'

    and person.id.medicareNumber = 123456

from Account as account

where account.owner.id.country = 'AU'

    and account.owner.id.medicareNumber = 123456

第二个查询跨越两个表PersonAccount。是一个多表查询,但此感受不到多表查询的效果。

行多持久化的情况下,class关键字用来存取一个例的鉴别值discriminator value)。嵌入where子句中的Java名,将被作为该类鉴别值。例如:

from Cat cat where cat.class = DomesticCat

where子句中的属性表达式必以基本型或java.lang.String尾,不要使用型属性尾,例如AccountPerson属性,而PersonName属性,NamefirstName属性。

看下面的情形:

from Account as a where a.person.name.firstName  like "dd%" //正确

from Account as a where a.person.name like "dd%" //错误

4.3.7  表达式

HQL的功能非常丰富,where子句后支持的运算符异常丰富,不包括SQL的运算符,包括EJB-QL的运算符等。

where子句中允使用大部分SQL支持的表达式:

  ● 数学运算符+*/等。

  ● 制比运算符=>=<=<>!=like等。

  ● 逻辑运算符andornot等。

  ● innot inbetweenis nullis not nullis emptyis not emptymember ofnot member of等。

  ● 简单casecase ... when ... then ... else ... endcasecase when ... then ... else ...       end等。

  ● 字符串接符value1 || value2或使用字符串接函数concat(value1 , value2)

  ● 时间操作函数current_date()current_time()current_timestamp()second()minute()hour()day()month()year()等。

  ● HQL支持EJB-QL 3.0所支持的函数或操作substring()trim()lower()upper()length()locate()abs()sqrt()bit_length()coalesce()nullif()等。

  ● 支持数据转换函数,如cast(... as ...),第二个参数是Hibernate型名,或者extract(... from ...),前提是底数据支持ANSI cast()extract()

  如果底数据支持如下行函数sign()trunc()rtrim()sin()HQL句也完全可以支持。

  ● HQL句支持使用?作参数占位符,JDBC的参数占位符一致,也可使用命名参数占位符号,方法是在参数名前加冒号 :,例如 :start_date:x1等。

  当然,也可在where子句中使用SQL常量,例如'foo'69'1970-01-01 10:00:         01.0'等。

  ● 可以在HQL句中使用Java public static final 型的常量,例如eg.Color.TABBY

除此之外,where子句支持如下的特殊关键字用法。

  ● inbetween...and可按如下方法使用:

from DomesticCat cat where cat.name between 'A' and 'B'

from DomesticCat cat where cat.name in ( 'Foo','Bar','Baz')

  ● 当然,也支持not innot between...and的使用,例如:

from DomesticCat cat where cat.name not between 'A' and 'B'

from DomesticCat cat where cat.name not in ( 'Foo','Bar','Baz' )

  ● 子句is nullis not null可以被用来测试,例如:

from DomesticCat cat where cat.name is null;

from Person as p where p.address is not null;

如果在Hibernate配置文件中行如下声明:

<property name="hibernate.query.substitutions">true 1, false 0</property>

上面的声明表明,HQL转换SQL,将使用字符10来取代关键truefalse然后将可以在表达式中使用布表达式,例如:

from Cat cat where cat.alive = true

  ● size关键字用于返回一个集合的大小,例如:

from Cat cat where cat.kittens.size > 0

from Cat cat where size(cat.kittens) > 0

  ● 于有序集合,可使用minindexmaxindex函数代表最小与最大的索引序数。同理,可以使用minelementmaxelement函数代表集合中最小与最大的元素。         例如:

from Calendar cal where maxelement(cal.holidays) > current date

from Order order where maxindex(order.items) > 100

from Order order where minelement(order.items) > 10000

  ● 可以使用SQL函数anysomeallexistsin操作集合里的元素,例如:

//操作集合元素

select mother from Cat as mother, Cat as kit

where kit in elements(foo.kittens)

//pname属性等于集合中某个元素的name属性

select p from NameList list, Person p

where p.name = some elements(list.names)

//操作集合元素

from Cat cat where exists elements(cat.kittens)

from Player p where 3 > all elements(p.scores)

from Show show where 'fizard' in indices(show.acts)

注意sizeelementsindicesminindexmaxindexminelementmaxelement 等,只能在where子句中使用。

  ● where子句中,有序集合的元素(arrays, lists, maps)可以通[ ]运算符访问。例如:

//items是有序集合属性,items[0]代表第一个元素

from Order order where order.items[0].id = 1234

//holidaysmap集合属性,holidays[national day]代表其中一个元素

select person from Person person, Calendar calendar

where calendar.holidays['national day'] = person.birthDay

and person.nationality.calendar = calendar

//下面同使用list 集合和map集合属性

select item from Item item, Order order

where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11

select item from Item item, Order order

where order.items[ maxindex(order.items) ] = item and order.id = 11

[]中的表达式甚至可以是一个算表达式,例如:

select item from Item item, Order order

where order.items[ size(order.items) - 1 ] = item

借助于HQL,可以大大选择语句的写,提高查询语句的可性,看下面的HQL句:

select cust

from Product prod,

    Store store

    inner join store.customers cust

where prod.name = 'widget'

    and store.location.name in ( 'Melbourne', 'Sydney' )

    and prod = all elements(cust.currentOrder.lineItems)

如果翻SQL句,将成如下形式:

SELECT cust.name, cust.address, cust.phone, cust.id, cust.current_order

FROM customers cust,

    stores store,

    locations loc,

    store_customers sc,

    product prod

WHERE prod.name = 'widget'

    AND store.loc_id = loc.id

    AND loc.name IN ( 'Melbourne', 'Sydney' )

    AND sc.store_id = store.id

    AND sc.cust_id = cust.id

    AND prod.id = ALL(

        SELECT item.prod_id

        FROM line_items item, orders o

        WHERE item.order_id = o.id

            AND cust.current_order = o.id

    )

4.3.8  order by子句

查询返回的列表(list)可以根据件属性的任何属性行排序,例如:

from Person as p

order by p.name, p.age

可使用ascdesc关键字指定升序或降序的排序规则,例如:

from Person as p

order by p.name asc , p.age desc

如果没有指定排序规则,默采用升序规则。即是否使用asc关键字是没有区的,加asc是升序排序,不加asc也是升序排序。

4.3.9  group by子句

返回聚集查询可以持久化件属性的属性行分,分所使用的group by子句。看下面的HQL查询语句:

select cat.color, sum(cat.weight), count(cat)

from Cat cat

group by cat.color

似于SQL规则,出select后的属性,要在聚集函数中,要group by的属性列表中。看下面示例:

//select后出idgroup by之后,而name属性在聚集函数中

select foo.id, avg(name), max(name)

from Foo foo join foo.names name

group by foo.id

having子句用于组进过滤,如下:

select cat.color, sum(cat.weight), count(cat)

from Cat cat

group by cat.color

having cat.color in (eg.Color.TABBY, eg.Color.BLACK)

注意:having子句用于组进过滤,因此having子句只能在有group by子句才可以使用,没有group by子句,不能使用having子句。

HibernateHQL句会直接翻成数据SQL句。因此,如果底数据支持的having子句和group by子句中出一般函数或聚集函数,HQL句的having子句和order by 子句中也可以出一般函数和聚集函数。

例如:

select cat

from Cat cat

join cat.kittens kitten

group by cat

having avg(kitten.weight) > 100

order by count(kitten) asc, sum(kitten.weight) desc

注意:group by子句与 order by子句中都不能包含算表达式。

4.3.10  查询

如果底数据支持子查询可以在HQL句中使用子查询。与SQL中子查询相似的是,HQL中的子查询也需要使用()括起来。如:

from Cat as fatcat

where fatcat.weight > ( select avg(cat.weight) from DomesticCat cat )

如果select中包含多个属性,则应该使用元构造符:

from Cat as cat

where not ( cat.name, cat.color ) in (

    select cat.name, cat.color from DomesticCat cat

)

4.3.11  fetch关键

于集合属性,Hibernate采用延策略。例如,于持久化Person,有集合属性scores。加Person,默不加scores属性。如果Session关闭Person例将无法访问关联scores属性。

了解决该问题,可以在Hibernate映射文件中取消延或使用fetch join,例如:

from Person as p join p.scores

上面的fetch句将会初始化personscores集合属性。

如果使用了属性级别的延迟获取,可以使用fetch all propertiesHibernate立即抓取那些原本需要延的属性,例如:

from Document fetch all properties order by name

from Document doc fetch all properties where lower(doc.name) like '%cats%'

4.3.12  命名查询

HQL查询还支持将查询所用的HQL句放入配置文件中,而不是代中。通过这种方式,可以大大提供程序的解耦。

使用query元素定命名查询,下面是定命名查询的配置文件片段:

<!--  命名查询 -->

<query name="myNamedQuery">

    <!--  确定命名查询HQL -->

    from Person as p where p.age > ?

</query>

命名的HQL查询可以直接通Session访问用命名查询的示例代如下:

private void findByNamedQuery()throws Exception

{

    //Hibernate Session

    Session sess = HibernateUtil.currentSession();

    //始事

    Transaction tx = sess.beginTransaction();

    System.out.println("行命名查询");

    //用命名查询

    List pl = sess.getNamedQuery("myNamedQuery")

                        //参数赋值

                       .setInteger(0 , 20)

                        //返回全部

                       .list();

    //历结果集

    for (Iterator pit = pl.iterator() ; pit.hasNext(); )

    {

        Person p = ( Person )pit.next();

        System.out.println(p.getName());

    }

    //提交事

    tx.commit();

    HibernateUtil.closeSession();

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值