Hbername hqlクエリコードの例


本研究の主な内容はHbernate hqlクエリです。具体的には以下の通りです。
HQL紹介
Hbernate言語の検索(HQuery Language)、それは完全に対象に向かう検索語句で、検索機能は非常に強いです。多形・関連性などの特性を備え、HQLクエリーもHbernate公式おすすめの検索方法です。
次のケースを通して、関連の問い合わせ方法を分析します。
Class.java:

public class Classes {
	/*  ID*/
	private int id;
	/*    */
	private String name;
	/*        */
	private Set<Student> students;
	//  setter getter  
}
Student.java:

public class Student {
	/*  ID*/
	private int id;
	/*    */
	private String name;
	/*        */
	private Classes classes;
	//  setter getter  
}
クラスes.hbm.xml:

<?xml version="1.0"?> 
<!DOCTYPE hibernate-mapping PUBLIC  
  "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 
<hibernate-mapping package="com.lixue.bean"> 
  <!--   lazy false --> 
  <class name="Classes" table="t_classes" lazy="false"> 
    <id name="id"> 
      <generator class="native"/> 
    </id> 
    <property name="name"/> 
    <!--       ,inverse="true"          --> 
    <set name="students" inverse="true"> 
       <key column="classesid"/> 
      <one-to-many class="Student"/> 
    </set> 
  </class> 
</hibernate-mapping> 
Student.hbm.xml:

<?xml version="1.0"?> 
<!DOCTYPE hibernate-mapping PUBLIC  
  "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 
<hibernate-mapping package="com.lixue.bean"> 
  <class name="Student" table="t_student"> 
    <id name="id"> 
      <generator class="native"/> 
    </id> 
    <!--        --> 
    <property name="name"/> 
    <!--       ,         --> 
    <many-to-one name="classes" column="classesid"/> 
  </class> 
</hibernate-mapping> 
1.クエリーの単一属性:

/*         ,                */ 
      List<String> students = session.createQuery("select name from Student").list(); 
      /*  */ 
      for (Iterator<String> iter=students.iterator(); iter.hasNext();) { 
        String name = (String)iter.next(); 
        System.out.println(name); 
      } 
注:単一の属性を検索すると、返ってくるのはセットで、セット要素のタイプはこの属性のタイプです。
2.複数の属性をクエリーし、オブジェクトの配列を返します。

/*      ,        */ 
      List<Object[]> students = session.createQuery("select id, name from Student").list(); 
      /*  */ 
      for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) { 
        Object[] obj = (Object[])iter.next(); 
        System.out.println(obj[0] + ", " + obj[1]); 
      } 
注:複数の属性を調べて返したのは、1つのタイプが対象配列のセットです。これはよく分かります。単一の属性が戻りのセット要素のタイプが属性のタイプですが、複数のタイプは?それは対象配列で処理しなければなりません。つまりObject[]です。
3.複数の属性を調べ、対象のタイプのセットを返します。

/*                ,                           */ 
      List students = session.createQuery("select new Student(id, name) from Student").list(); 
      /*  */ 
      for (Iterator iter=students.iterator(); iter.hasNext();) { 
        Student student = (Student)iter.next(); 
        System.out.println(student.getId() + ", " + student.getName()); 
      } 
注:私たちの第二の方法で戻ってきたのはオブジェクトの配列だけでなく、エンティティオブジェクトに対応する構造関数を設定し、照会対象によって照会し、エンティティタイプのセットに戻ることができます。
4.エイリアスを使ってクエリーを行います。

/*      */ 
      List<Object[]> students = session.createQuery("select s.id, s.name from Student s").list(); 
      /*  */ 
      for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) { 
        Object[] obj = (Object[])iter.next(); 
        System.out.println(obj[0] + ", " + obj[1]); 
      } 
5.クエリーエンティティオブジェクト:

/*             */ 
      List<Student> students = session.createQuery("from Student").list(); 
      /*  */ 
      for (Iterator<Student> iter=students.iterator(); iter.hasNext();) { 
        Student student = (Student)iter.next(); 
        System.out.println(student.getName()); 
      }
注:照会エンティティは、fromクラス名の形式を直接使用することができます。

/*  select       */ 
      List<Student> students = session.createQuery("select s from Student s").list(); 
      /*  */ 
      for (Iterator<Student> iter=students.iterator(); iter.hasNext();) { 
        Student student = (Student)iter.next(); 
        System.out.println(student.getName()); 
      }
注:selectキーワードを使用するには、別名を使用する必要があります。もう一つ注意してください。hqlはselect*の形を避けてください。
6.N+1の問題:

/** 
       *   list               ,         
       * 
       * Hibernate: select student0_.id as id0_, student0_.name as name0_, 
       * student0_.createTime as createTime0_, student0_.classesid as classesid0_ 
       * from t_student student0_ 
       */ 
      List<Student> students = session.createQuery("from Student").list(); 
      /*  */ 
      for (Iterator<Student> iter=students.iterator(); iter.hasNext();) { 
        Student student = (Student)iter.next(); 
        System.out.println(student.getName()); 
      }
注:リスト()を使用して、オブジェクトクエリを行います。ステートメントは一つだけ発行されます。つまり、エンティティオブジェクトデータを取得するステートメントです。

/** 
       *    N+1  ,   N+1      N+1 sql   
       * 
       * 1:      id      
       * Hibernate: select student0_.id as col_0_0_ from t_student student0_ 
       * 
       * N:  id  N sql  ,        
       * Hibernate: select student0_.id as id0_0_, student0_.name as name0_0_, 
       * student0_.createTime as createTime0_0_, student0_.classesid as classesid0_0_ 
       * from t_student student0_ where student0_.id=? 
       * 
       */ 
      Iterator<Student> iter = session.createQuery("from Student").iterate(); 
      /*  */ 
      while (iter.hasNext()) { 
        Student student = (Student)iter.next(); 
        System.out.println(student.getName()); 
      } 
注:iterator()方式で対象クエリを行うと、N+1の文が発行されます。まず、ステートメントを出してエンティティオブジェクトのIDを調べ、それぞれのIDに基づいてNのステートメントを発行してNのオブジェクトを調べます。この中で形式性能は比較的に悪いです。

/*  List                 session    */ 
      List<Student> students = session.createQuery("from Student").list(); 
      /*  */ 
      for (Iterator<Student> iter=students.iterator(); iter.hasNext();) { 
        Student student = (Student)iter.next(); 
        System.out.println(student.getName()); 
      } 
      System.out.println("-----------------------------------------------------"); 
      /** 
       *    N+1   
       * 
       *     list         session    (    ),    iterate    
       *          id     ,   id           ,               
       *        id   sql  ,           
       * 
       * Iterate           ,       ,    N+1   
       * 
       */ 
      Iterator<Student> iter = session.createQuery("from Student").iterate(); 
      /*  */ 
      while (iter.hasNext()) { 
        Student student = (Student)iter.next(); 
        System.out.println(student.getName()); 
      } 
注:実際にハイベルナーがiteratorを提供する方式で調べたのは性能を向上させるためですが、なぜ逆に助けになりましたか?理由はiterator()が一級キャッシュからデータを取ったからです。キャッシュにデータがあれば、その効率は間違いなく相当な力になりますが、初めて調べた時にキャッシュにデータがあるはずがないです。上のコードはN+1の問題を避けることができます。リスト()で調べてから、一級キャッシュでまとめてデータが存在します。iterator()を使うと、効率が非常に高くなります。
7.条件照会:

/*        (         ,     )*/ 
      List<Object[]> students = session.createQuery("select s.id, s.name from Student s where s.name like '%0%'").list(); 
      /*  */ 
      for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) { 
        Object[] obj = (Object[])iter.next(); 
        System.out.println(obj[0] + ", " + obj[1]); 
      }
注:条件検索は元のsqlと同じで、whereキーワードです。また、通常は別名を使うのが便利で、上記のプログラムは複数の属性を照会するため、オブジェクト配列タイプのセットを返します。オブジェクト配列の要素は対応する属性です。
8.プレースホルダの形式クエリ:

/*    */ 
      List<Object[]> students = session.createQuery("select s.id, s.name from Student s where s.name like ?") 
          .setParameter(0, "%0%") 
          .list(); 
      /*  */ 
      for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) { 
        Object[] obj = (Object[])iter.next(); 
        System.out.println(obj[0] + ", " + obj[1]); 
      } 
注:SQL注入はプレースホルダの形で行うことができます。
9.カスタムパラメータの形式:

/*    */ 
      List<Object[]> students = session.createQuery("select s.id, s.name from Student s where s.name like :myname") 
          .setParameter("myname", "%0%") 
          .list(); 
      /*    */ 
      for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) { 
        Object[] obj = (Object[])iter.next(); 
        System.out.println(obj[0] + ", " + obj[1]); 
      } 
注:like:myname番号の後ろにスペースがないので、間違えます。
10.クエリー条件はinの形式です。

[java] view plain copy
/*  in   ,        */ 
      List<Object[]> students = session.createQuery("select s.id, s.name from Student s where s.id in(:ids)") 
          .setParameterList("ids", new Object[]{1, 2, 3, 4, 5}) 
          .list(); 
      /*  */ 
      for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) { 
        Object[] obj = (Object[])iter.next(); 
        System.out.println(obj[0] + ", " + obj[1]); 
      }
注:inの後ろの括弧の中に一つの形の参があればいいです。パラメータ値を設定すると、対象の配列を通して値を伝えることができます。
11.データベースの個人化関数を使用します。

/*  2009-08   ,    mysql        */ 
      List<Object[]> students = session.createQuery("select s.id, s.name from Student s where date_format(s.createTime, '%Y-%m')=?") 
          .setParameter(0, "2009-08") 
          .list(); 
      /*  */ 
      for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) { 
        Object[] obj = (Object[])iter.next(); 
        System.out.println(obj[0] + ", " + obj[1]); 
      } 

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 
      /*  2009-08-01  2009-08-20   ,    mysql        */ 
      List<Object[]> students = session.createQuery("select s.id, s.name from Student s where s.createTime between ? and ?") 
          .setParameter(0, sdf.parse("2009-08-01 00:00:00")) 
          .setParameter(1, sdf.parse("2009-08-20 23:59:59")) 
          .list(); 
      /*  */ 
      for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) { 
        Object[] obj = (Object[])iter.next(); 
        System.out.println(obj[0] + ", " + obj[1]); 
      }
12.元の生態系のSQL文を使う:

/*  select *         SQL  ,      hql      ,                 */ 
      List<Object[]> students = session.createSQLQuery("select * from t_student").list(); 
      /*  */ 
      for (Iterator<Object[]> iter = students.iterator(); iter.hasNext();) { 
        Object[] obj = (Object[]) iter.next(); 
        System.out.println(obj[0] + ", " + obj[1]); 
      }
注:hqlはselect*の照会形式をサポートしていませんが、Hybernaは元の生態系のSQL文をサポートしています。SQL文を使って照会することができます。また、HQLのように複数の属性を照会するので、対象配列の種類の集合を返します。
13.改ページクエリ

/*    ,setFirstResult(1)            ;setMaxResult(2)      2   */ 
      List students = session.createQuery("from Student") 
            .setFirstResult(1) 
            .setMaxResults(2) 
            .list(); 
      /*  */ 
      for (Iterator iter=students.iterator(); iter.hasNext();) { 
        Student student = (Student)iter.next(); 
        System.out.println(student.getName()); 
      } 
14.ナビゲーションクエリ

/*    ,s.classes.name                (              ,      )*/ 
      List<Student> students = session.createQuery("from Student s where s.classes.name like '%2%'") 
            .list(); 
      /*  */ 
      for (Iterator<Student> iter=students.iterator(); iter.hasNext();) { 
        Student student = (Student)iter.next(); 
        System.out.println(student.getName()); 
      }
注:上記の質問文のs.lasses.nameは学生ナビゲーションからクラスクラスクラスクラスクラスクラスのクラス名を取得しています。逆にナビゲーションしてもいいです。クラスナビゲーションから学生に属性をもらっています。また、クラス名の中に2が含まれているすべての学生を調べるという意味です。
15.内部接続クエリ

/*   ,  join     */ 
    List<Object[]> students = session.createQuery("select c.name, s.name from Student s join s.classes c") 
          .list(); 
    /*  */ 
    for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) { 
      Object[] obj = (Object[])iter.next(); 
      System.out.println(obj[0] + ", " + obj[1]); 
    } 
注:内連結キーワードはジョインで、別名とナビゲーションで接続しています。上記の質問文の意味は、学級表と学級表から学級名と学生名を調べます。(内連結は属性が必要です。例えば、学級がないと学生がいないと調べられない)。
16.左接続

/*        left join*/ 
      List<Object[]> students = session.createQuery("select c.name, s.name from Student s left join s.classes c") 
            .list(); 
      /*  */ 
      for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) { 
        Object[] obj = (Object[])iter.next(); 
        System.out.println(obj[0] + ", " + obj[1]); 
      }
注:左接続のキーワードを使うと、left joinです。上のような質問文の意味は、学生とクラス表から学級名と学生名が分かります。左連結ですので、学級がない学生も調べられます。
17.右接続

[java] view plain copy
/*       right join*/ 
      List<Object[]> students = session.createQuery("select c.name, s.name from Student s right join s.classes c") 
            .list(); 
      /*  */ 
      for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) { 
        Object[] obj = (Object[])iter.next(); 
        System.out.println(obj[0] + ", " + obj[1]); 
      }
注:右接続のキーワードを使うのはright joinです。上記の質問文の意味は、学生とクラス表から学級名と学生名を調べました。右に接続しているので、学生のいないクラスが調べられます。
18.統計クエリ

Long count = (Long)session.createQuery("select count(*) from Student").uniqueResult();
注:hqlの中には統計検索だけがあります。uniqueResoult()は一つの結果セットだけを表しています。ループタイプを返します。
19.複合クエリ

/*    */ 
      String hql = "select c.name, count(s) from Classes c join c.students s group by c.name order by c.name"; 
       
      List<Object[]> students = session.createQuery(hql).list(); 
      /*  */ 
      for (int i=0; i<students.size(); i++) { 
        Object[] obj = (Object[])students.get(i); 
        System.out.println(obj[0] + ", " + obj[1]); 
      }
注:hqlは同様にグループ、ソートなどをサポートします。上の文の意味は、各クラスの名前を調べて、各クラスの学生数を調べて、クラス名によってグループ分けして、クラス名によって並べ替えます。
締め括りをつける
以上が、本論文でHibernate hqlクエリコードの実例のすべての内容です。皆様のご協力をお願いします。興味のある方は引き続き当駅の他のテーマを参照してください。友達のサポートに感謝します。