1. 程式人生 > >Hibernate HQL引數化查詢,動態

Hibernate HQL引數化查詢,動態

Hibernate中對動態查詢引數繫結提供了豐富的支援,那麼什麼是查詢引數動態繫結呢?其實如果我們熟悉傳統JDBC程式設計的話,我們就不難理解查詢引數動態繫結,如下程式碼傳統JDBC的引數繫結:
  PrepareStatement pre=connection.prepare(“select * from User where user.name=?”);
  pre.setString(1,”zhaoxin”);
  ResultSet rs=pre.executeQuery();
  在Hibernate中也提供了類似這種的查詢引數繫結功能,而且在Hibernate中對這個功能還提供了比傳統JDBC操作豐富的多的特性,在Hibernate中共存在4種引數繫結的方式,下面我們將分別介紹:
  A、 按引數名稱繫結:
  在HQL語句中定義命名引數要用”:”開頭,形式如下:
  Query query=session.createQuery(“from User user where user.name=:customername and user:customerage=:age ”);
  query.setString(“customername”,name);
  query.setInteger(“customerage”,age);
  上面程式碼中用:customername和:customerage分別定義了命名引數customername和customerage,然後用Query介面的setXXX()方法設定名引數值,setXXX()方法包含兩個引數,分別是命名引數名稱和命名引數實際值。
  B、 按引數位置邦定:
  在HQL查詢語句中用”?”來定義引數位置,形式如下:
  Query query=session.createQuery(“from User user where user.name=? and user.age =? ”);
  query.setString(0,name);
  query.setInteger(1,age);
  同樣使用setXXX()方法設定繫結引數,只不過這時setXXX()方法的第一個引數代表邦定引數在HQL語句中出現的位置編號(由0開始編號),第二個引數仍然代表引數實際值。
  注:在實際開發中,提倡使用按名稱邦定命名引數,因為這不但可以提供非常好的程式可讀性,而且也提高了程式的易維護性,因為當查詢引數的位置發生改變時,按名稱邦定名引數的方式中是不需要調整程式程式碼的。
  C、 setParameter()方法:
  在Hibernate的HQL查詢中可以通過setParameter()方法邦定任意型別的引數,如下程式碼:
  String hql=”from User user where user.name=:customername ”;
  Query query=session.createQuery(hql);
  query.setParameter(“customername”,name,Hibernate.STRING);
  如上面程式碼所示,setParameter()方法包含三個引數,分別是命名引數名稱,命名引數實際值,以及命名引數對映型別。對於某些引數型別setParameter()方法可以根據引數值的Java型別,猜測出對應的對映型別,因此這時不需要顯示寫出對映型別,像上面的例子,可以直接這樣寫:
  query.setParameter(“customername”,name);但是對於一些型別就必須寫明對映型別,比如java.util.Date型別,因為它會對應Hibernate的多種對映型別,比如Hibernate.DATA或者Hibernate.TIMESTAMP。
  D、 setProperties()方法:(setEntity())
  在Hibernate中可以使用setProperties()方法,將命名引數與一個物件的屬性值繫結在一起,如下程式程式碼:
  Customer customer=new Customer();
  customer.setName(“pansl”);
  customer.setAge(80);
  Query query=session.createQuery(“from Customer c where c.name=:name and c.age=:age ”);
  query.setProperties(customer);
  setProperties()方法會自動將customer物件例項的屬性值匹配到命名引數上,但是要求命名引數名稱必須要與實體物件相應的屬性同名。
  這裡還有一個特殊的setEntity()方法,它會把命名引數與一個持久化物件相關聯,如下面程式碼所示:
  Customer customer=(Customer)session.load(Customer.class,”1”);
  Query query=session.createQuery(“from Order order where order.customer=:customer ”);
  query. setEntity(“customer”,customer);
  List list=query.list();
  上面的程式碼會生成類似如下的SQL語句:
  Select * from order where customer_ID=’1’;
  E、 使用繫結引數的優勢:
  我們為什麼要使用繫結命名引數?任何一個事物的存在都是有其價值的,具體到繫結引數對於HQL查詢來說,主要有以下兩個主要優勢:
  ①、 可以利用資料庫實施效能優化,因為對Hibernate來說在底層使用的是PrepareStatement來完成查詢,因此對於語法相同引數不同的SQL語句,可以充分利用預編譯SQL語句快取,從而提升查詢效率。
  ②、 可以防止SQL Injection安全漏洞的產生:
  SQL Injection是一種專門針對SQL語句拼裝的攻擊方式,比如對於我們常見的使用者登入,在登入介面上,使用者輸入使用者名稱和口令,這時登入驗證程式可能會生成如下的HQL語句:
  “from User user where user.name=’”+name+”’ and user.password=’”+password+”’ ”
  這個HQL語句從邏輯上來說是沒有任何問題的,這個登入驗證功能在一般情況下也是會正確完成的,但是如果在登入時在使用者名稱中輸入”zhaoxin or ‘x’=’x”,這時如果使用簡單的HQL語句的字串拼裝,就會生成如下的HQL語句:
  “from User user where user.name=’zhaoxin’ or ‘x’=’x’ and user.password=’admin’ ”;
  顯然這條HQL語句的where字句將會永遠為真,而使使用者口令的作用失去意義,這就是SQL Injection攻擊的基本原理。
  而使用繫結引數方式,就可以妥善處理這問題,當使用繫結引數時,會得到下面的HQL語句:

  from User user where user.name=’’zhaoxin’’ or ‘’x=’’x’’ ‘ and user.password=’admin’;由此可見使用繫結引數會將使用者名稱中輸入的單引號解析成字串(如果想在字串中包含單引號,應使用重複單引號形式),所以引數繫結能夠有效防止SQL Injection安全漏洞。

具體示例:

配置檔案

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>

   <!-- <session-factory>

        <property name="myeclipse.connection.profile">JDBC for MySQL</property>

        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>

        <property name="connection.url">jdbc:mysql://localhost:3306/book</property>

        <property name="connection.username">root</property>

        <property name="connection.password"></property>

        <property name="hibernate.show_sql">true</property>

        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="hibernate.format_sql">true</property>
        <!–生成特定資料庫sql–>
        <property name="hibernate.hbm2ddl.auto">update</property>
        <!–thread指定當前執行緒來跟蹤管理–>
        <property name="current_session_context_class">thread</property>


        <mapping resource="Dog.xml"></mapping>

    </session-factory>
-->

    <session-factory>
        <property name="connection.driver_class">oracle.jdbc.OracleDriver</property>
        <property name="connection.url">jdbc:oracle:thin:@localhost:1521:orcl</property>
        <property name="connection.username">sll</property>
        <property name="connection.password">sll</property>
        <!-- SQL dialect -->
        <property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>

<property name="current_session_context_class">thread</property>
        <property name="show_sql">true</property>

        <!--<property name="hbm2ddl.auto">update</property>-->
        <property name="connection.autocommit">true</property>
     <!--   <mapping resource="cn/happy/hibernate01/Cat.hbm.xml"/>
        <mapping resource="cn/happy/hibernate02/Dept.hbm.xml"/>-->
        <mapping resource="cn/happy/hibernate03hql/Emp.hbm.xml"/>
    </session-factory>
</hibernate-configuration>


小配置

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.happy.hibernate02">
<class name="Dept" table="Dept"  schema="sll">
    <id name="deptno" column="deptno">
        <generator class="native"></generator>
    </id>
    <property name="deptname"></property>
</class>

</hibernate-mapping>


另外一個 我是2個包裡面的所以用2個

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.happy.hibernate03hql">
    <class name="cn.happy.hibernate03hql.Emp" table="EmpSLL">
        <id name="empno"  column="empno" >
            <generator class="native" />
        </id>
        <property name="enmae" column="enmae"/>
        <property name="job" column="job"/>
        <property name="mgr" column="mgr"/>
        <property name="hiredate" column="hiredate"/>
        <property name="sal" column="sal"/>
        <property name="comm" column="comm"/>
        <property name="deptno" column="deptno"/>
    </class>
        </hibernate-mapping>

實體類

package cn.happy.hibernate02;

/**
 * Created by linlin on 2017/9/25.
 */
public class Dept {
    private Integer deptno;
    private String deptname;

    public Dept() {
    }

    public Dept(Integer deptno, String deptname) {
        this.deptno = deptno;
        this.deptname = deptname;
    }

    public Integer getDeptno() {
        return deptno;
    }

    public void setDeptno(Integer deptno) {
        this.deptno = deptno;
    }

    public String getDeptname() {
        return deptname;
    }

    public void setDeptname(String deptname) {
        this.deptname = deptname;
    }
}


動態查詢 需要的實體類

package cn.happy.hibernate03hql;

import cn.happy.hibernate02.Dept;

import java.util.Date;

/**
 * Created by linlin on 2017/9/25.
 */
public class Emp {
    private Long empno;
    private String enmae;
    private String job;
    private Long mgr;
    private Date hiredate;
    private Long sal;
    private Long comm;
    private Byte deptno;

private conEmp ce;

    public conEmp getCe() {
        return ce;
    }

    public void setCe(conEmp ce) {
        this.ce = ce;
    }

    public Long getEmpno() {
        return empno;
    }

    public void setEmpno(Long empno) {
        this.empno = empno;
    }

    public String getEnmae() {
        return enmae;
    }

    public void setEnmae(String enmae) {
        this.enmae = enmae;
    }

    public String getJob() {
        return job;
    }

    public void setJob(String job) {
        this.job = job;
    }

    public Long getMgr() {
        return mgr;
    }

    public void setMgr(Long mgr) {
        this.mgr = mgr;
    }

    public Date getHiredate() {
        return hiredate;
    }

    public void setHiredate(Date hiredate) {
        this.hiredate = hiredate;
    }

    public Long getSal() {
        return sal;
    }

    public void setSal(Long sal) {
        this.sal = sal;
    }

    public Long getComm() {
        return comm;
    }

    public void setComm(Long comm) {
        this.comm = comm;
    }

    public Byte getDeptno() {
        return deptno;
    }

    public void setDeptno(Byte deptno) {
        this.deptno = deptno;
    }
}

package cn.happy.hibernate03hql;

import java.util.Date;

/**
 * Created by linlin on 2017/9/25.
 */
public class conEmp {
    private Date hiredateEnd;
    private Date hiredateStart;
    private String job;
    private Long sal;


    public conEmp(Date hiredateEnd, Date hiredateStart, String job, Long sal) {
        this.hiredateEnd = hiredateEnd;
        this.hiredateStart = hiredateStart;
        this.job = job;
        this.sal = sal;
    }

    public conEmp() {
    }

    public String getJob() {
        return job;
    }

    public void setJob(String job) {
        this.job = job;
    }


    public Long getSal() {
        return sal;
    }

    public void setSal(Long sal) {
        this.sal = sal;
    }

    public Date getHiredateStart() {
        return hiredateStart;
    }

    public void setHiredateStart(Date hiredateStart) {
        this.hiredateStart = hiredateStart;
    }

    public Date getHiredateEnd() {
        return hiredateEnd;
    }

    public void setHiredateEnd(Date hiredateEnd) {
        this.hiredateEnd = hiredateEnd;
    }

}


具體的測試類

package cn.happy.test;


import cn.happy.hibernate01.Cat;
import cn.happy.hibernate02.Dept;
import cn.happy.hibernate03hql.Emp;
import cn.happy.hibernate03hql.conEmp;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Before;
import org.junit.Test;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * Created by linlin on 2017/9/22.
 */
public class test0925 {
    Configuration cfg;
    Transaction tx;
    Session session;
    SessionFactory factory;
    @Before
    public void myBefore(){
        //建立配置物件
        cfg = new Configuration().configure("Hibernate.cfg.xml");
        //根據配置物件建立SessionFactory
       factory = cfg.buildSessionFactory();
        //根據SessionFactory建立Session
        session= factory.openSession();
        //在Session建立後開啟事務
        tx = session.beginTransaction();
    }

    @Test
    public void test01() {

        Cat dog = new Cat();
        dog.setName("哈哈2");
        dog.setAge(2);
        session.save(dog);
      //  tx.commit();
        session.close();
        System.out.println("新增成功!!!");

    }

    @Test
    public void test03() {

        Cat dog = new Cat();
       dog.setId(8);
        dog.setName("蘇us");
        dog.setAge(11);
        session.saveOrUpdate(dog);
        tx.commit();
        session.close();
        System.out.println("ok!!!");

    }

    @Test
    public void test0333() {

        Dept dog = new Dept();
        dog.setDeptno(2);
        dog.setDeptname("保潔部");
        session.save(dog);
        tx.commit();
        session.close();
        System.out.println("ok!!!");

    }
//查詢所有
    @Test
    public void test0select() {

    String hql="from Dept";
        Query query = session.createQuery(hql);
        List<Dept> list=query.list();
        for (Dept item:list){
            System.out.println(item.getDeptname());
        }
        System.out.println("ok");
    }
//檢索部分記錄
    @Test
    public void test0sel8ct() {

        String hql="from Dept where deptname='開發部'";
        Query query = session.createQuery(hql);
        List<Dept> list=query.list();
        for (Dept item:list){
            System.out.println(item.getDeptname());
        }
        System.out.println("ok");
    }

    @Test
    public void test8ct() {

        String hql="select deptname from Dept";
        Query query = session.createQuery(hql);
        List<Dept> list=query.list();
        System.out.println(list);
        System.out.println("ok");
    }
    //部分多列
    @Test
    public void test0sel8() {

        String hql="select deptno,deptname from Dept";
        Query query = session.createQuery(hql);
        List<Object[]> list=query.list();
        for (Object[] item:list){
            for (Object child:item)
            System.out.println(child);
        }
        System.out.println("ok");
    }
//檢索部分集合 強型別
    @Test
    public void testl8() {

        String hql="select new Dept(deptno,deptname) from Dept";
        Query query = session.createQuery(hql);
        List<Dept> list=query.list();
        for (Dept item:list){
            System.out.println(item.getDeptname());
        }
        System.out.println("ok");
    }

    @Test
    public void testl834() {

        String hql="from Dept where deptname=?";
        Query query = session.createQuery(hql);
        query.setParameter(0,"開發部");
        List<Dept> list=query.list();
        for (Dept item:list){
            System.out.println(item.getDeptname());
        }
        System.out.println("ok");
    }

    @Test
    public void testl() {

        String hql="from Dept where deptname=:deptname";
        Query query = session.createQuery(hql);
        query.setParameter("deptname","開發部");
        List<Dept> list=query.list();
        for (Dept item:list){
            System.out.println(item.getDeptname());
        }
        System.out.println("ok");
    }
    @Test
    public void test4() {

        String hql="from Dept dept where dept.deptname=deptname";
        Query query = session.createQuery(hql);
     Dept dd=new Dept();
     dd.setDeptname("開發部");
     query.setProperties(dd);
        List<Dept> list=query.list();
        for (Dept item:list){
            System.out.println(item.getDeptname());
        }
        System.out.println("ok");
    }

    //動態查詢
    @Test
    public void testselect() {


      conEmp c=new conEmp();
      c.setSal(1000L);
      c.setJob("CLERK");
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
        Date fromdate=null;
        Date enddate=null;
        try {
            fromdate=sdf.parse("1981-04-01");
            enddate=sdf.parse("1985-09-09");
        } catch (ParseException e) {
            e.printStackTrace();
        }
        c.setHiredateEnd(enddate);
        c.setHiredateStart(fromdate);
        String hql="from Emp where 1=1 ";
        StringBuffer sb=new StringBuffer(hql);

        if(c.getJob()!=null){
            sb.append(" and job=:job ");
        }
        if(c.getSal()!=null){
            sb.append(" and sal>:sal ");
        }
        if(c.getHiredateStart()!=null){
            sb.append(" and hiredate>=:hiredateStart ");
        }
        if(c.getHiredateEnd()!=null){
            sb.append(" and hiredate<=:hiredateEnd ");
        }
        Query query = session.createQuery(sb.toString());
        query.setProperties(c);
        List<Emp> list=query.list();
        for (Emp item:list){
            System.out.println(item.getEmpno());
        }
    }
}