zoukankan      html  css  js  c++  java
  • Hibernate sql查询

    Hibernate还支持使用SQL查询,使用SQL查询可以利用某些数据库的特性,或者用于将原有的JDBC应用迁移到Hibernate应用上。使用命名的SQL查询还可以将SQL语句放在配置文件中配置,从而提高程序的解耦,命名SQL查询还可以用于调用存储过程。

    如果是一个新的应用,通常不要使用SQL查询。

    SQL查询是通过SQLQuery接口来表示的,SQLQuery接口是Query接口的子接口,因此完全可以调用Query接口的方法:

       ● setFirstResult(),设置返回结果集的起始点。

       ● setMaxResults(),设置查询获取的最大记录数。

       ● list(),返回查询到的结果集。

    但SQLQuery比Query多了两个重载的方法:

       ● addEntity,将查询到的记录与特定的实体关联。

       ● addScalar,将查询的记录关联成标量值。

    执行SQL查询的步骤如下:

    (1)获取Hibernate Session对象;

    (2)编写SQL语句;

    (3)以SQL语句作为参数,调用Session的createSQLQuery方法创建查询对象;

    (4)如果SQL语句包含参数,调用Query的setXxx方法为参数赋值;

    (5)调用SQLQuery对象的addEntity或addScalar方法将选出的结果与实体或标量值关联;

    (6)调用Query的list方法返回查询的结果集。

    看下面的SQL查询示例:

    private void test()

    {

        //获取Hibernate Session对象

        Session session = HibernateUtil.currentSession();

        //开始事务

        Transaction tx = session.beginTransaction();

        //编写SQL语句

        String sqlString = "select {s.*} from student s where s.name like '马军'";

        //以SQL语句创建SQLQuery对象

        List l = session.createSQLQuery(sqlString)

                        //将查询到的记录与特定实体关联起来

                        .addEntity("s",Student.class)

                        //返回全部的记录集

                        .list();

        //遍历结果集

        Iterator it = l.iterator();

        while (it.hasNext())

        {

            //因为将查询结果与Student类关联,因此返回的是Student集合

            Student s = (Student)it.next();

            Set enrolments = s.getEnrolments();

            Iterator iter = enrolments.iterator();

            while(iter.hasNext())

            {

                Enrolment e = (Enrolment)iter.next();

                System.out.println(e.getCourse().getName());

            }

        }

        //提交事务

        tx.commit();

        //关闭Session

        HibernateUtil.closeSession();

    }

    上面的示例显示了将查询记录关联成一个实体的示例。事实上,SQL查询也支持将查询结果转换成标量值,转换成标量值可以使用addScalar方法,如:

    Double max = (Double) session.createSQLQuery("select max(cat.weight) as maxWeight from cats cat")

            .addScalar("maxWeight", Hibernate.DOUBLE);

            .uniqueResult();

    或者:
    1. StringBuffer queryStr = new StringBuffer();   
    2. queryStr.append("select count(*) AA,");   
    3. queryStr.append("sum(st.num1) BB,sum(st.num2) CC,");   
    4. queryStr.append("max(st.cost1) DD,min(st.cost2) EE,");   
    5. queryStr.append("st.col1 FF from TBXXX st")   
    6. .append(" where ")   
    7. .append(SQLQuerySetup.createfilterStr(filter))   
    8. .append(" group by st.col1");   
    9.   
    10. query = session.createSQLQuery(queryStr.toString());   
    11. query.addScalar("AA"new org.hibernate.type.IntegerType());   
    12. query.addScalar("BB"new org.hibernate.type.IntegerType());   
    13. query.addScalar("CC"new org.hibernate.type.IntegerType());   
    14. query.addScalar("DD"new org.hibernate.type.IntegerType());   
    15. query.addScalar("EE"new org.hibernate.type.IntegerType());   
    16. query.addScalar("FF"new org.hibernate.type.IntegerType());   
    17. return query.list();  

    注意2个问题 
    1.Query 没有addScalar()方法,使用SQLQuery才有addScalar()方法 
    2.如果查询的结果集的字段为id,count(*) as count,则如果只 
    addScalar("count",type),将得不到id的值,需要加上addScalar("id",type),也就是要把每一个字段都要addScalar()

    使用SQL查询,如果需要将查询到的结果转换成特定实体,就要求为选出的字段命名别名。这别名不是随意命名的,而是以“/”实例名.属性名“/”的格式命名,例如:

    //依次将多个选出的字段命名别名,命名别名时都以ss作为前缀,ss是关联实体的别名

    String sqlStr = "select stu.studentId as {ss.studentNumber},"

            + "stu.name as {ss.name} from "

            + "student as stu where stu.name like '杨海华'";

    List l = session.createSQLQuery(sqlStr)

                //将查询出的ss实例,关联到Student类

                .addEntity("ss",Student.class)

                .list();

    在第一个示例中,以{s.*}代表该表的全部字段,且关联实例的别名也被指定为s。

    注意:如果不使用{s.*}的形式,就可让实体别名和表别名互不相同。关联实体的类型时,被关联的类必须有对应的setter方法。

    4.5.1 命名SQL查询

    可以将SQL语句不放在程序中,而放在配置文件中,这种方式以松耦合的方式配置SQL语句,可以提高程序解耦。

    在Hibernate的映射文件中定义查询名,然后确定查询所用的SQL语句,然后就可以直接调用该命名SQL查询。在这种情况下,不需要调用addEntity()方法,因为在配置命名SQL查询时,已经完成了查询结果与实体的关联。

    下面是命名SQL查询的配置片段:

    <!-- 每个sql-query元素定义一个命名SQL查询 -->

    <sql-query name="mySqlQuery">

        <!-- 关联返回的结果与实体类 -->

        <return alias="s" class="Student"/>

            <!-- 定义命名SQL查询的SQL语句 -->

             SELECT {s.*}

            from student s WHERE s.name like'杨海华'

    </sql-query>

    sql-query元素是hibernate-mapping元素的子元素。因此,sql-query定义的名可以直接通过Session访问,上面定义的mySqlQuery查询可以直接访问,下面是使用该命名SQL查询的示例代码:

    private void testNamedSQl()

    {

        //获取Hibernate Session对象

        Session session = HibernateUtil.currentSession();

        //开始事务

        Transaction tx = session.beginTransaction();

        //调用命名查询,直接返回结果

        List l = session.getNamedQuery("mySqlQuery")

                             .list();

        //遍历结果集

        Iterator it = l.iterator();

        while (it.hasNext())

        {

            //在定义SQL查询时,已经将结果集与Student类关联起来

            //因此,集合里的每个元素都是Student实例

            Student s = (Student)it.next();

            Set enrolments = s.getEnrolments();

            Iterator iter = enrolments.iterator();

            while(iter.hasNext())

            {

                Enrolment e = (Enrolment)iter.next();

                System.out.println("=====================================");

                System.out.println(e.getCourse().getName());

                System.out.println("=====================================");

            }

        }

        tx.commit();

        HibernateUtil.closeSession();

    }

    4.5.2 调用存储过程

    Hibernate 3增加了存储过程的支持,该存储过程只能返回一个结果集。

    下面是Oracle 9i的存储过程示例:

    CREATE OR REPLACE FUNCTION selectAllEmployments

        RETURN SYS_REFCURSOR

    AS

        st_cursor SYS_REFCURSOR;

    BEGIN

        OPEN st_cursor FOR

    SELECT EMPLOYEE, EMPLOYER,

    STARTDATE, ENDDATE,

    REGIONCODE, EID, VALUE, CURRENCY

    FROM EMPLOYMENT;

          RETURN st_cursor;

    END;

    如果需要使用该存储过程,可以先将其定义成命名SQL查询,例如:

    <!-- 定义命名SQL查询,name属性指定命名SQL查询名 -->

    <sql-query name="selectAllEmployees_SP" callable="true">

        <!-- 定义返回列与关联实体类属性之间的映射 -->

        <return alias="emp" class="Employment">

            <!-- 依次定义每列与实体类属性的对应 -->

            <return-property name="employee" column="EMPLOYEE"/>

            <return-property name="employer" column="EMPLOYER"/>

            <return-property name="startDate" column="STARTDATE"/>

            <return-property name="endDate" column="ENDDATE"/>

            <return-property name="regionCode" column="REGIONCODE"/>

            <return-property name="id" column="EID"/>

            <!-- 将两列值映射到一个关联类的组件属性 -->

            <return-property name="salary">

                <!-- 映射列与组件属性之间的关联 -->

                <return-column name="VALUE"/>

                <return-column name="CURRENCY"/>

            </return-property>

        </return>

        { ? = call selectAllEmployments() }

    </sql-query>

    调用存储过程还有如下需要注意的地方:

       ● 因为存储过程本身完成了查询的全部操作,所以调用存储过程进行的查询无法使用setFirstResult()/setMaxResults()进行分页。

       ● 存储过程只能返回一个结果集,如果存储过程返回多个结果集,Hibernate将仅处理第一个结果集,其他将被丢弃。

       ● 如果在存储过程里设定SET NOCOUNT ON,将有更好的性能表现。当然也可以没有该设定。

  • 相关阅读:
    [P4721] 【模板】分治 FFT
    [GYM102452E] Erasing Numbers
    [LOJ6220] sum
    [CF776B] Sherlock and His Girlfriend
    [LOJ6087] 毒瘤题
    [LOJ2612] 花匠
    [LOJ529] 自然语言
    [CTSC2017] 吉夫特
    [LOJ6671] EntropyIncreaser 与 Minecraft
    [LOJ3196] 挂架
  • 原文地址:https://www.cnblogs.com/kelin1314/p/1821897.html
Copyright © 2011-2022 走看看