国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

Java的Hibernate框架中用于操作數據庫的HQL語句講解

2019-11-26 14:42:19
字體:
來源:轉載
供稿:網友

 上次我們一起學習了用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=? 
 
 
 3)我們可以在HQL語句中加上SQL函數:
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表數據如下:

201613144805709.png (279×87)

t_user表數據如下:

201613144821427.png (260×88)

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中運行可以看到結果:

201613144900835.png (790×67)

我們可以看到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中進行查出,看到:

201613145004498.png (792×91)

我們看到,盡管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中執行后可以看到結果:

201613145040175.png (794×89)

這里我們可以看到address為Test4的并沒有相應的user與它對應,但它還是并查出來了,right outer join是指把右邊表的記錄全部查出。
 fetch的情況如上,如果不明白可以看一下inner join fetch。
 

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 井陉县| 大庆市| 防城港市| 河源市| 林西县| 青浦区| 彰化县| 同心县| 嘉荫县| 濮阳市| 海安县| 安陆市| 观塘区| 金山区| 曲沃县| 和龙市| 县级市| 禄丰县| 云阳县| 广安市| 岳池县| 锡林郭勒盟| 高邑县| 衡阳县| 海城市| 浦城县| 平乡县| 建瓯市| 红原县| 察哈| 东辽县| 兴城市| 无为县| 麻城市| 绥芬河市| 九龙坡区| 基隆市| 广东省| 龙南县| 尚义县| 保靖县|