13.hibernate的native sql查詢(轉自xiaoluo501395377)

來源:互聯網
上載者:User

標籤:

在我們的hibernate中,除了我們常用的HQL查詢以外,還非常好的支援了原生的SQL查詢,那麼我們既然使用了hibernate,為什麼不都採用hibernate推薦的HQL查詢語句呢?這是因為HQL查詢語句雖然方便我們查詢,但是基於HQL的查詢會將查詢出來的對象儲存到hibernate的緩衝當中,如果在我們的一個大型項目中(資料量超過了百萬級),這個時候如果使用hibernate的HQL查詢的話,會一次將我們查詢的物件查詢出來後放到緩衝中,這個時候會影響我們的效率,所以當在大型項目中使用hibernate時我們的最佳實務就是--使用原生的SQL查詢語句,而不使用HQL語句,因為通過SQL查詢的話,是不會經過hibernate的緩衝的。接下來我們就來看看hibernate的原生SQL查詢

1.標量查詢

在hibernate中,我們如果使用原生SQL查詢的話,是通過SQLQuery介面進行的,我們首先來看看我們最基本的查詢:

session.createSQLQuery("select * from t_student s").list()session.createSQLQuery("select ID,NAME,SEX from t_student s").list()

這就建立了最簡單的兩條SQL查詢語句,此時返回的資料庫表的欄位值是儲存在一個Object[]數組中的,數組中的每個元素就是查詢出來的t_student表中的每個欄位值,Hibernate會通過ResultSetMetadata來判斷每個欄位值的存放位置以及類型,接下來我們看下標量查詢:

List<Object[]> stus = (List<Object[]>)session.createSQLQuery("select * from t_student s")                                                    .addScalar("ID")                                                    .addScalar("NAME")                                                    .setFirstResult(0).setMaxResults(20)                                                    .list();

這個查詢語句指定了查詢的字串以及返回的欄位和類型

這條查詢語句仍然會返回一個Object[]類型的數組,但是此時就不會通過ResultSetMetadata,而是我們明確指定的ID,NAME,SEX,此時雖然查詢語句中有 * 將所有的欄位查詢出來,但是這個時候僅僅只會返回我們指定的三個欄位值,其類型還是由ResultSetMetada來指定的。

2.實體查詢

①返回一個實體物件

上述的標量查詢返回的裸資料,儲存到了Object[]數組當中,我們如果要一個實體物件,將其儲存到實體物件時就可以使用 addEntity()方法來實現:

@Test    public void testSql1()    {        Session session = null;        try        {            session = HibernateUtil.openSession();            /*             * 原生的SQL語句查詢,會將t_student表的所有欄位查出來,存放的一個Object[]數組當中             * 如果希望轉換成實體物件,只需要調用 addEntity(Student.class)即可,這時,會首先匹配             * Student對象裡面的屬性是否全部查詢出來,如果沒有,則報錯(如果這個類是實體類)             * 注意:如果要調用addEntity方法,這個類必須是實體類,即加了@Entity註解或者在XML中配置了實體類             * 映射關係             */            List<Student> stus = (List<Student>)session.createSQLQuery("select * from t_student s")                                                    .addEntity(Student.class)                                                    .setFirstResult(0).setMaxResults(20)                                                    .list();            for(Student stu : stus)            {                System.out.println(stu.getName());            }        }        catch (Exception e)        {            e.printStackTrace();        }        finally        {            HibernateUtil.close(session);        }    }

這時我們就指定了將查詢出來的對象存進Student這個實體類中,注意如果使用了實體物件,那麼在查詢時要將實體物件中有的屬性全部在SQL語句中查詢出來,否則就會報錯

②返回多個實體物件

有的時候我們可能不只查詢出一個實體物件,在使用串連查詢時候,我們可能需要將幾個表的資料都查詢出來,並存放到對應的實體物件中去,這個時候我們應該怎麼寫呢?先看下如下一種寫法:

List<Object[]> stus = (List<Object[]>)session.createSQLQuery("select stu.*, cla.*, spe.*"                    + " from t_student stu left join t_classroom cla on stu.rid=cla.id"                    + " left join t_special spe on spe.id=cla.sid where stu.name like ?")                                                    .addEntity("stu", Student.class)                                                    .addEntity("cla", Classroom.class)                                                    .addEntity("spe", Special.class)                                                    .setFirstResult(0).setMaxResults(20)                                                    .setParameter(0, "%張%")                                                    .list();

我們這裡通過addEntity的一個重載方法給每個別名指定了一個關聯的實體類,這個時候就會出現欄位名衝突的問題,我們的本意是查詢出三個實體物件,分別取得其name屬性,但是name屬性在這三張表中的欄位都是name,這個時候查詢出來的三個實體物件中的屬性值都是一樣的。我們如果要解決這個方法,只需要用一個 {} 花括弧預留位置將每個表的所有屬性值括起來即可。如下:

@Test    public void testSql3()    {        Session session = null;        try        {            session = HibernateUtil.openSession();            /**             * 當使用串連查詢查詢多個對象時,可以通過addEntity("alias", XXX.class)方法來根據             * 資料庫表的別名來引入多個實體類,這時如果需要將查詢出來的所有的對象分別存入實體類中,             * 只需要在查詢出來的對象上添加 {} 號即可,此時就會自動幫我們分類             */            List<Object[]> stus = (List<Object[]>)session.createSQLQuery("select {stu.*}, {cla.*}, {spe.*}"                    + " from t_student stu left join t_classroom cla on stu.rid=cla.id"                    + " left join t_special spe on spe.id=cla.sid where stu.name like ?")                                                    .addEntity("stu", Student.class)                                                    .addEntity("cla", Classroom.class)                                                    .addEntity("spe", Special.class)                                                    .setFirstResult(0).setMaxResults(20)                                                    .setParameter(0, "%張%")                                                    .list();            for(Object[] obj : stus)            {                Student stu = (Student)obj[0];                Classroom cla = (Classroom)obj[1];                Special spe = (Special)obj[2];                System.out.println(stu.getName() + ", " + cla.getName() + ", " + spe.getName());            }        }        catch (Exception e)        {            e.printStackTrace();        }        finally        {            HibernateUtil.close(session);        }    }

③返回不受hibernate管理的實體物件

我們有時候的需求是這樣的,將每個表其中的一些欄位查詢出來,然後存放到一個javabean對象中,但是我們的這個bean對象又不需要存放到資料庫,不需要設定成實體物件,這個時候我們往往會建立一個 DTO 的資料轉送對象來存放我們要儲存的屬性,例如定義了一個 StudentDTO 對象:

public class StudentDTO{    private int sid;    // 學生id    private String sname;  // 學生姓名    private String sex;  // 學生性別    private String cname;  // 班級名    private String spename;  // 專業名        public StudentDTO(){}    public StudentDTO(int sid, String sname, String sex, String cname,            String spename)    {        super();        this.sid = sid;        this.sname = sname;        this.sex = sex;        this.cname = cname;        this.spename = spename;    }  ................}

這個時候我們來看看我們的查詢語句:

@Test    public void testSql4()    {        Session session = null;        try        {                /**             * 對於非Entity實體物件的類,我們如果要保持資料,可以通過定義一個DTO對象             * 然後調用setResultTransformer(Transformers.aliasToBean(StudentDTO.class))方法             * 來返回一個不受管的Bean對象             */            session = HibernateUtil.openSession();            List<StudentDTO> stus = (List<StudentDTO>)session.createSQLQuery("select "                    + "stu.id as sid, stu.name as sname, stu.sex as sex, cla.name as cname, spe.name as spename"                    + " from t_student stu left join t_classroom cla on stu.rid=cla.id"                    + " left join t_special spe on spe.id=cla.sid where stu.name like ?")                                                    .setResultTransformer(Transformers.aliasToBean(StudentDTO.class))                                                    .setFirstResult(0).setMaxResults(20)                                                    .setParameter(0, "%張%")                                                    .list();            for(StudentDTO std : stus)            {                System.out.println(std.getSname() + ", " + std.getCname() + ", " + std.getSpename());            }        }        catch (Exception e)        {            e.printStackTrace();        }        finally        {            HibernateUtil.close(session);        }    }

我們要將查詢出來的這些不同的表的欄位存放到一個不是實體物件當中,就可以調用 .setResultTransformer(Transformers.aliasToBean(StudentDTO.class)) 方法來建立一個非受管的 bean 對象,這個時候就hibernate就會將屬性值存放到這個 bean 對象當中,注意查詢出來的表的欄位值存放到bean對象中,是通過調用 bean對象的 setter方法,如果該屬性在bean對象中沒有setter方法,則會報錯

 

本篇隨筆主要分析了一下如何來通過原生的SQL語句查詢我們需要的資訊,我們一定要記住,當資料量非常大的時候,強烈建議使用原生的SQL去查詢資料,而不要使用HQL來查詢,這樣其實使用hibernate來說效率其實也不差,但是我們的增、刪、改的操作則完全可以交給hibernate來完成。

13.hibernate的native sql查詢(轉自xiaoluo501395377)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.