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

首頁 > 學院 > 開發設計 > 正文

使用HibernateSQLQuery(轉)

2019-11-14 15:02:53
字體:
來源:轉載
供稿:網友

原文地址:http://itindex.net/detail/51776-hibernate-sqlquery-sql,重新排了一下版

Hibernate對原生SQL查詢的支持和控制是通過SQLQuery接口實現的,這種方式彌補了HQL、Criterion查詢的不足,在操作和使用上往往更加的自由和靈活,如果使用得當,數據庫操作的效率還會得到不同程度的提升。

Hibernate對原生SQL查詢的支持和控制是通過SQLQuery接口實現的。通過session接口,我們能夠很方便的創建一個SQLQuery(SQLQuery是一個接口,在Hibernate4.2.2之前,默認返回的是SQLQuery的實現類——SQLQueryImpl對象,在下文中出現的SQLQuery如非注明,都是指該子類)對象來進行原生SQL查詢:

session.createSQLQuery(String sql);

SQLQuery實現了Query接口,因此你可以使用Query接口中提供的API來獲取數據。

最簡單的示例

session.createSQLQuery("select * from note").list();//獲取所有查詢結果 
session.createSQLQuery("select * from note where id = 1").uniqueResult();//僅獲取第一條結果

使用預處理SQL

預處理SQL的好處自然不必多說,除了眾所周知的能夠防止SQL注入攻擊外,還能夠在一定程度上提高SQL的查詢效率。SQLQuery提供了眾多的接口來分別設置不同類型的參數,諸如setBigDecimal、setBinary、setDouble等,詳參SQLQuery的javaDoc,此處不再贅述。這里僅重點說一下通用的SQL參數設置接口setParameter。

如下代碼示范了如何使用SQLQuery執行預處理SQL:

SQLQuery query = session.createSQLQuery("select * from note where id = ?");//設置第一個參數的值為12,即查詢ID=12的note query.setParameter(0,12);List list = query.list();

這里需要注明一點,無論是通過不同類型參數的設置接口來設置SQL參數,還是通過setParameter來設置參數,下標都是從0開始的,而不是從1開始的

使用自定義的結果轉換器處理查詢結果

SQLQuery 接口預留了setResultTransformer接口以實現使用用戶自定義的ResultTransformer結果集轉換器處理查詢結果。 ResultTransformer接口非常簡單,只有兩個方法,分別用來轉換單行數據和所有結果數據。經過自定義ResultTransformer生成的實體,并未加入Session,因此是非受管實體。

如下代碼,示范了如何將單行數據裝入LinkedHashMap對象中:

    query.setResultTransformer(newResultTransformer(){        @Override        public Object transformTuple(Object[] values,String[] columns){            Map<String,Object> map =new LinkedHashMap<String,Object>(1);            int i =0;            for(String column : columns){                 map.put(column, values[i++]);            }            return map;        }        @Override        public List transformList(List list){            return list;            }        }    );

 如果不設置自定義的ResultTransformer轉換器,則Hibernate將每行返回結果的數據按照結果列的順序裝入Object數組中。

這里介紹一個工具類: Transformers,它提供了一些常用的轉換器,能夠幫助我們快速轉換結果集,如Transformers.aliasToBean(Note.class)能夠將查詢結果依別名注入到Note實體中。

使用標量

使用SQLQuery執行原生SQL時,Hibernate會使用ResultSetMetadata來判定返回的標量值的實際順序和類型。如果要避免過多的使用ResultSetMetadata,或者只是為了更加明確的指名返回值,可以使用addScalar()。

session.createSQLQuery("select * from note where id = 1")        .addScalar("id",LongType.INSTANCE)        .addScalar("name",StringType.INSTANCE)        .addScalar("createtime",DateType.INSTANCE);

這個查詢指定了SQL查詢字符串,要返回的字段和類型.它仍然會返回Object數組,但是此時不再使用ResultSetMetdata,而是明確的將id,name和 createtime按照Long, String和Date類型從resultset中取出。同時,也指明了就算query是使用*來查詢的,可能獲得超過列出的這三個字段,也僅僅會返回這三個字段。

對全部或者部分的標量值不設置類型信息也是可以的:

session.createSQLQuery("select * from note where id = 1").addScalar("id").addScalar("name").addScalar("createtime",DateType.INSTANCE);

沒有被指定類型的字段將仍然使用ResultSetMetdata獲取其類型。 注意,字段不區分大小寫,同時不能夠指定不存在的字段!

關于從ResultSetMetaData返回的java.sql.Types是如何映射到Hibernate類型,是由方言(Dialect)控制的。假 若某個指定的類型沒有被映射,或者不是你所預期的類型,你可以通過Dialet的registerHibernateType調用自行定義。

如果僅指定了一個scalar,那么...

Date createTime =(Date)session.createSQLQuery("select * from note where id = 1").addScalar("createtime",DateType.INSTANCE).uniqueResult();

如果我們的SQL語句使用了聚合函數,如count、max、min、avg等,且返回結果僅一個字段,那么Hibernate提供的這種提取標量結果的方式就非常便捷了。

實體查詢

上面的查詢都是返回標量值的,也就是從resultset中返回的“裸”數據。下面展示如何通過addEntity()讓原生查詢返回實體對象。

session.createSQLQuery("select * from note where id = 1").addEntity(Note.class); 
session.createSQLQuery("select id,name,createtime from note where id = 1").addEntity(Note.class);

這個查詢指定SQL查詢字符串,要返回的實體。假設Note被映射為擁有id,name和createtime三個字段的類,以上的兩個查詢都返回一個List,每個元素都是一個Note實體。

假若實體在映射時有一個many-to-one的關聯指向另外一個實體,在查詢時必須也返回那個實體,否則會導致發生一個"column not found"的數據庫錯誤。這些附加的字段可以使用*標注來自動返回,但我們希望還是明確指明,看下面這個具有指向Dog的many-to-one的例 子:

session.createSQLQuery("select id,note,createtime,author from note where id = ?").addEntity(Note.class);

author字段即為Note實體和Author實體的關聯字段,只需在查詢時得到該字段的值,Hibernate即可使用該值找到對應的關聯實體。如上例中,note.getAuthor()即可返回當前Note所屬的Author對象。

處理關聯和集合類

通過提前抓取將Author連接獲得,而避免初始化PRoxy帶來的額外開銷也是可能的。這是通過addJoin()方法進行的,這個方法可以讓你將關聯或集合連接進來。

session.createSQLQuery("select {note.*}, {author.*} from note note, user author where note.author = author.id")
.addEntity("note",Note.class)
.addJoin("author","note.author");

上面的例子是多對一的關聯查詢,反過來做一對多的關聯查詢也是可以的。如下的例子中,author.notes表示該用戶發表的所有日記(Note),Set集合類型: 

session.createSQLQuery("select {author.*},{note.*} from note note, user author where author.id = ? and note.author = author.id")
.addEntity("author",User.class)
.addJoin("note","author.notes");

注意:join查詢會在每行返回多個實體對象,處理時需要注意。

別名和屬性引用

假若SQL查詢連接了多個表,同一個字段名可能在多個表中出現多次,這會導致SQL錯誤。不過在我們可以通過使用占位符來完美地解決這一問題。

其實在上例中已經用到了占位符:

session.createSQLQuery("select {note.*}, {author.*} from note note, user author where note.author = author.id")
.addEntity("note",Note.class)
.addJoin("author","note.author");

這個查詢指明SQL查詢語句,其中包含占位附來讓Hibernate注入字段別名,查詢并返回的實體。

上面使用的{note.*}和{author.*}標記是作為“所有屬性”的簡寫形式出現的,當然你也可以明確地羅列出字段名。但如下的范例代碼中我們讓Hibernate來為每個屬性注入SQL字段別名,字段別名的占位符是表別名 + . + 屬性名。

注意:屬性名區分大小寫,而且不能夠在where子句中使用占位符。

SQLQuery query = session.createSQLQuery(
"select note.id as {note.id},note as {note.note},createtime as {note.createTime},author as {note.author}, {author.*}
  from note, user author
  where note.id = ? and note.author = author.id");
query.addEntity("note",Note.class);
query.addJoin("author","note.author");

大多數情況下,上面的別名注入方式可以滿足需要,但在使用更加復雜的映射,比如復合屬性、通過標識符構造繼承樹,以及集合類等等情況下,則需要更加復雜的別名注入方式。

下表列出了使用別名注射參數的不同方式:

 別名注入(alias injection names) 描述 語法 示例
 簡單屬性 {[aliasname].[propertyname] A_NAME as {item.name}
 復合屬性 {[aliasname].[componentname].[propertyname]} CURRENCY as {item.amount.currency}, VALUE as {item.amount.value}
 實體辨別器 {[aliasname].class} DISC as {item.class}
 實體的所有屬性 {[aliasname].*} {item.*}
 集合鍵(collection key) {[aliasname].key} ORGID as {coll.key}
 集合id {[aliasname].id} EMPID as {coll.id}
 集合元素 {[aliasname].element} XID as {coll.element}
 集合元素的屬性 {[aliasname].element.[propertyname]} NAME as {coll.element.name}
 集合元素的所有屬性 {[aliasname].element.*} {coll.element.*}
 集合的所有屬性 {[aliasname].*} {coll.*}

在hbm文件中描述結果集映射信息,并在查詢中使用

對于一些復雜的結果集映射,往往需要像MyBatis那樣在文件中手動配置好,然后在程序中使用。幸運的是Hibernate也提供了類似的功能,你可以使用自己配置的結果集映射來處理返回的結果集數據:

SQLQuery query = session.createSQLQuery("select note.id as {note.id},note as {note.note},createtime as {note.createTime},author as {note.author}, {author.*} from note, user author where note.id = ? and note.author = author.id");//使用在hbm文件中配置的自定義結果集映射 query.setResultSetMapping("noteAnduthor"); query.list();

執行更新操作

使用SQLQuery執行數據庫更新操作比較容易,除了像查詢時那樣需要指定SQL語句(如有需要還需設置SQL參數)外,僅需調用executeUpdate()方法,即可提交更新操作。代碼如下所示:

session.createSQLQuery("update createtime = ? from note where note.id = ?");query.setDate(0,newDate()); query.setLong(1,1L); query.executeUpdate();

 

executeUpdate方法的返回結果為改變的數據庫記錄的行數。

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 泰兴市| 湘西| 佛坪县| 吉隆县| 苍梧县| 洮南市| 凉山| 江阴市| 历史| 阳东县| 竹北市| 绍兴市| 阿荣旗| 雷州市| 陈巴尔虎旗| 紫阳县| 华池县| 清新县| 安达市| 米易县| 连江县| 内乡县| 巴彦县| 大同县| 郸城县| 万载县| 嘉义县| 武安市| 新野县| 鄂伦春自治旗| 丰原市| 柳林县| 兴宁市| 丽江市| 稷山县| 海原县| 梅州市| 长岭县| 锡林郭勒盟| 仙游县| 电白县|