Ⅰ Hibernate中CriteriaQuery可以使用原生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(new ResultTransformer() {
@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");
大多數情況下,上面的別名注入方式可以滿足需要,但在使用更加復雜的映射,比如復合屬性、通過標識符構造繼承樹,以及集合類等等情況下,則需要更加復雜的別名注入方式。
下表列出了使用別名注射參數的不同方式:
Ⅱ Hibernate如何執行原生的SQL語句
hibernate本來就支持 原sql 調用執行sql的方法就行了 調用方法的時候注意看所需的參數
@Autowired
private SessionFactory sessionFactory;
sessionFactory.getCurrentSession().createSQLQuery(sql);
這樣就可以了
Ⅲ hibernate原生sql查詢單列返回的是什麼
其實是沒有具體的返回的,執行的結果是org.hibernate.impl.SQLQueryImpl,根據你對返回結果的邏輯來決定你返回的類型,比如java.util.List,調用它的list()方法,調用iterater方法則返回java.util.Iterator.返回String則調用SQLQueryImpl的父類AbstractQueryImpl的getQueryString()....
Ⅳ hibernate 使用原生sql執行 insert 插入數據時,怎麼才能得到自動增長主鍵的id
如果插入數據的用戶是唯一標識的話,可以在插入完成之後,去檢索該用戶插入的數據,比較id,那個最大的id即剛才插入數據的id。
Ⅳ hibernate執行原生sql和客戶端執行sql的區別
sql和客戶端執行sql的區別。
1、sql面向資料庫表查詢:sql:from後面跟的是表名where後用表中欄位做條件。
2、hql面向對象查詢:hql:from後面跟的類名+類對象where後用對象的屬性做條件。
3、在Hibernate中使用查詢時,一般使用燃並Hql查詢語句。HQL(HibernateQueryLanguage),即Hibernate的查詢語言跟脊磨SQL非常相像。HQL與SQL的最根本的區別,就是它是面向櫻段斗對象的。