Java的Hibernate框架頂用於操作數據庫的HQL語句講授。本站提示廣大學習愛好者:(Java的Hibernate框架頂用於操作數據庫的HQL語句講授)文章只能為提供參考,不一定能成為您想要的結果。以下是Java的Hibernate框架頂用於操作數據庫的HQL語句講授正文
前次我們一路進修了用Criteria停止相干的操作,但因為Criteria其實不是Hibernate官方推舉的查詢方法,我們也其實不多用。如今我們來看一下官方推舉的HQL,一路進修一下它的壯大。
說是HQL,也就是Hibernate查詢語句,和SQL有甚麼差別呢?一個字母的差別,哈哈。
固然不是如許,HQL和SQL的差別在於思惟的分歧,HQL是用面向對象的偏向停止查詢,而SQL則是對數據庫二維表停止查詢,這裡包括的是思惟的分歧。HQL現實上也是SQL,它由Hibernate幫我們在外部停止轉換,生成SQL。
1)空話不多說,我們直接看一下它的壯大。
from User
這個代碼很熟習吧,由於我們在SQL中常常也用到from 表名,但這裡有點分歧的是User在這裡其實不是表名,而是實體類的稱號,由hibernate幫我們停止映照。
聯想SQL語句,假如我們想查出某個屬性,而且依據某個屬性停止前提限制,很簡略可以獲得相似語句:
select usr.name,usr.age from User where usr.age > 20 and usr.age < 60
如許我們就查出了年紀年夜於20且小於60的User的姓名和年紀。很輕易懂得。
SQL語句中的and,or,like,<,>,=等都可以在HQL中停止應用。
須要留意的是當我們查詢多個屬性時,前往的成果是一個Object[]數組,而只要單個時是前往Object,這個須要分歧的解析方法,所以在查詢時須要留意。
2)固然,我們後面說了HQL是面向對象的,而我們如許做,就不是面向對象的思惟了。我們來改一下:
select new User(usr.name,usr.age) from User usr where usr.age > 20如許我們就把查詢到的成果放到了User對象中,留意,這裡挪用的是User的結構函數,User類中必需存在吸收兩個參數的User結構函數,不然會報錯,毛病信息年夜概以下:
Unable to locate appropriate constructor on class [org.hibernate.tutorial.domain8.User]
它找不到適合的結構函數。很明確,加上吸收對應參數的結構函數便可以了。
留意,下面當我們停止查出的時刻並沒有查出響應的ID,假如此時我們挪用saveOrUpdate辦法時,它現實上履行的是保留的操作。
我們看一下測試代碼:
我在履行完下面的查詢語句後,停止上面的操作:
while(iter.hasNext()) { User user = (User)iter.next(); user.setName("sun2"); session.saveOrUpdate(user); }
這時候Hibernate的語句為:
Hibernate: insert into USER (USER_NAME, age) values (?, ?)
它新拔出一條,而不是更新。
那末假如我們須要它停止更新的時刻就須要把ID一路查出:
select new User(usr.name,usr.age,usr.id) from User usr where usr.age > (select avg(usr.age) from usr)
記得修正User結構辦法。
這時候我們再履行我們的測試代碼,此時會獲得:
Hibernate: update USER set USER_NAME=?, age=? where USER_ID=?
select usr.name from User usr where usr.age > (select avg(usr.age) from usr)
這段HQL查出年紀年夜於均勻年紀的User的name。
4)在Hibernate 3中我們可以很便利地更新和刪除對象,而不用像2中須要先load然後再delete,我們可以直接一條語句弄定:
update User set name='123123' where name='sun33'
刪除語句相似:
delete User where name='123123'
5)Hibernate中也能夠便利地停止分組和排序,只需應用group by 和 order by 便可,這時候不多講了。
6)我們看到下面都是直接把值寫入停止查詢或更新的,假如我們須要靜態賦值,或賦值的太多,總不克不及跟JDBC一樣用字符串拼接吧,估量跨越5個,項目組的人都想罵娘了,呵呵。
照樣用著古代化的辦法,用占位符來取代然後再設置詳細值。
我們直接代碼:
Query query = session.createQuery("select new User(usr.name,usr.age,usr.id) from User usr where usr.name=?"); query.setString(0,"shun");
我們看到這類辦法跟我們直接用的PreparedStatement相似,都是經由過程set***停止設值的,但分歧的是,這裡的position從0開端,而PreparedStatement從1開端,這裡要特殊留意。
Hibernate2中還有session.find這類辦法的,但因為如今用的是3其實不多說它了。
下面我們用的這類占位符叫次序占位符,別的有一種叫援用占位符的,我們來看一下:
Query query = session.createQuery("select new User(usr.name,usr.age,usr.id) from User usr where usr.name=:name"); query.setParameter("name","shun");
看到我們HQL語句傍邊有一個:name如許的器械,這個就是援用占位符,我們只須要在前面經由過程setParameter停止設值便可,留意這裡的第一個參數須要對應HQL語句中的占位符的值。
固然,或許有人又會說,這個不面向對象,那末我們就又來面向對象一把:
起首弄一個類來封裝我們查詢的值
public class UserQuery { private String name; private int age; //省略Get/Set辦法 } Query query = session.createQuery("select new User(usr.name,usr.age,usr.id) from User usr where usr.name=:name"); UserQuery uq = new UserQuery(); uq.setName("shun"); query.setProperties(uq);
我們在代碼從直接經由過程此類停止封裝我們須要查詢的值。很面向對象吧。
有些項目組有一些奇異的劃定,不准在代碼中湧現SQL語句,假如這是一個標准,那我見過的我們公司的代碼,全體都是不及格的,杯具的一年夜堆字符串拼接,看著就愁悶啊。保護現有項目標人真是傷不起啊。
代碼中不許可湧現SQL語句,這是建議是不錯,但照樣要看場所。我們來看一下Hibernate怎樣把HQL設置裝備擺設在映照文件中。
直接看設置裝備擺設文件:
<query name="queryByName"> <![CDATA[ from User usr where usr.name=:name ]]> </query>
我們添加了一個如許的標簽,它注解外面是HQL語句。
當我們須要取到這個語句時,也只須要在代碼中參加一句:
Query query = session.getNamedQuery("queryByName");
如許也就取到了這個HQL語句。
HQL也能夠用SQL中的組合查詢,好比inner join,left outer join,right outer join,full join。
上面我們來看一下它們的用法:
照樣先看一下實體類,我們測試中要用到的:
public class TUser implements Serializable{ private static final long serialVersionUID = 1L; private int id; private int age; private String name; private Set<Address> addresses = new HashSet<Address>(); //省略Get/Set辦法 } public class Address implements Serializable{ private static final long serialVersionUID = 1L; private int id; private String address; private TUser user; //省略Get/Set辦法 }
上面我們看一下映照文件:
<hibernate-mapping package="org.hibernate.tutorial.domain6"> <class name="TUser" table="t_user" dynamic-insert="true" dynamic-update="true"> <id name="id" column="id"> <generator class="native" /> </id> <property name="name" type="java.lang.String" column="name"/> <property name="age" type="java.lang.Integer" column="age"/> <set name="addresses" cascade="all" table="t_address" inverse="true"> <key column="user_id" /> <one-to-many class="Address"/> </set> </class> </hibernate-mapping> <hibernate-mapping package="org.hibernate.tutorial.domain6"> <class name="Address" table="t_address" dynamic-insert="false" dynamic-update="false"> <id name="id" column="id" type="java.lang.Integer"> <generator class="native" /> </id> <property name="address" column="address" type="java.lang.String" /> <many-to-one name="user" class="TUser" column="user_id" not-null="true"></many-to-one> </class> </hibernate-mapping>
年夜家只需做一下響應的包名修正便可以了。
上面我們正式停止測試:
在測試前我們看一下表中的數據:
t_address表數據以下:
t_user表數據以下:
1)起首我們看一下inner join,它在HQL中由inner join fetch,留意這裡fetch的意思是指把須要的數據掏出來,假如不消fetch,我們掏出來的數據是Object[]數據類型的。
我們先看一下
from TUser usr inner join fetch usr.addresses
當我們運轉它時,我們看到hibernate輸入為:
Hibernate: select tuser0_.id as id1_0_, addresses1_.id as id0_1_, tuser0_.name as name1_0_, tuser0_.age as age1_0_, addresses1_.address as address0_1_, addresses1_.user_id as user3_0_1_, addresses1_.user_id as user3_0__, addresses1_.id as id0__ from t_user tuser0_ inner join t_address addresses1_ on tuser0_.id=addresses1_.user_id
我們在mysql中運轉可以看到成果:
我們可以看到hibernate將它轉換成inner join語句,並查出address。
我們看到成果中並沒有shun4這個記載,由於他並沒有響應的address與它記載。
而我們用inner join而不要fetch時,它打印的語句為:
Hibernate: select tuser0_.id as id1_0_, addresses1_.id as id0_1_, tuser0_.name as name1_0_, tuser0_.age as age1_0_, addresses1_.address as address0_1_, addresses1_.user_id as user3_0_1_ from t_user tuser0_ inner join t_address addresses1_ on tuser0_.id=addresses1_.user_id
仿佛語句沒甚麼差別,然則當我們查出來後它獲得的是Object[]數組類型的,這個解析的時刻需留意。
當我們不消fetch,而只是inner join時,我們須要如許來解析:
Query query = session.createQuery("from TUser usr inner join usr.addresses"); List list = query.list(); Iterator iter = list.iterator(); while(iter.hasNext()) { Object[] results = (Object[])iter.next(); for (int i = 0; i < results.length; i ++ ) { System.out.println(results[i]); } }
我們看到打印的成果:
org.hibernate.tutorial.domain6.TUser@16925b0 org.hibernate.tutorial.domain6.Address@914f6a org.hibernate.tutorial.domain6.TUser@787d6a org.hibernate.tutorial.domain6.Address@71dc3d org.hibernate.tutorial.domain6.TUser@1326484 org.hibernate.tutorial.domain6.Address@16546ef
它的每一個成果都是響應查出來的對象。
2)left outer join,這個相當於SQL的左銜接,我們直接看一下例子:
from TUser usr left outer join fetch usr.addresses
當我們運轉下面的語句時,hibernate打印出:
Hibernate: select tuser0_.id as id1_0_, addresses1_.id as id0_1_, tuser0_.name as name1_0_, tuser0_.age as age1_0_, addresses1_.address as address0_1_, addresses1_.user_id as user3_0_1_, addresses1_.user_id as user3_0__, addresses1_.id as id0__ from t_user tuser0_ left outer join t_address addresses1_ on tuser0_.id=addresses1_.user_id
我們在mysql中停止查出,看到:
我們看到,雖然shun4沒有對應的adress,但照樣把它查出來,left outer join是指把右邊表的記載全體查出。
沒有fetch的情形這裡就不講了。
3)接上去我們看一下right outer join,看名字確定就和left outer join有點關系的,我們直接看例子便可以顯著看出了。
from TUser usr right outer join fetch usr.addresses
我們履行它,獲得Hibernate輸入的成果語句為:
Hibernate: select tuser0_.id as id1_0_, addresses1_.id as id0_1_, tuser0_.name as name1_0_, tuser0_.age as age1_0_, addresses1_.address as address0_1_, addresses1_.user_id as user3_0_1_, addresses1_.user_id as user3_0__, addresses1_.id as id0__ from t_user tuser0_ right outer join t_address addresses1_ on tuser0_.id=addresses1_.user_id我們在mysql中履行後可以看到成果:
這裡我們可以看到address為Test4的並沒有響應的user與它對應,但它照樣並查出來了,right outer join是指把左邊表的記載全體查出。
fetch的情形如上,假如不明確可以看一下inner join fetch。