`
haohao-xuexi02
  • 浏览: 215476 次
  • 性别: Icon_minigender_2
  • 来自: 北京
社区版块
存档分类
最新评论

Native SQL查询

阅读更多

你也可以使用你的数据库的Native SQL语言来查询数据。这对你在要使用数据库的某些特性的时候(比如说在查询提示或者Oracle中的 CONNECT关键字),这是非常有用的。这就能够扫清你把原来直接使用SQL/JDBC 的程序迁移到基于 Hibernate应用的道路上的障碍。

Hibernate3允许你使用手写的sql来完成所有的create,update,delete,和load操作(包括存储过程)

16.1. 使用SQLQuery

对原生SQL查询执行的控制是通过SQLQuery接口进行的,通过执行Session.createSQLQuery()获取这个接口。最简单的情况下,我们可以采用以下形式:

List cats = sess.createSQLQuery("select * from cats")
    .addEntity(Cat.class)
    .list();

这个查询指定了:

  • SQL查询字符串

  • 查询返回的实体

这里,结果集字段名被假设为与映射文件中指明的字段名相同。对于连接了多个表的查询,这就可能造成问题,因为可能在多个表中出现同样名字的字段。下面的方法就可以避免字段名重复的问题:

List cats = sess.createSQLQuery("select {cat.*} from cats cat")
    .addEntity("cat", Cat.class)
    .list();

这个查询指定了:

  • SQL查询语句,它带一个占位符,可以让Hibernate使用字段的别名.

  • 查询返回的实体,和它的SQL表的别名.

addEntity()方法将SQL表的别名和实体类联系起来,并且确定查询结果集的形态。

addJoin()方法可以被用于载入其他的实体和集合的关联.

List cats = sess.createSQLQuery(
        "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
    )
    .addEntity("cat", Cat.class)
    .addJoin("kitten", "cat.kittens")
    .list();

原生的SQL查询可能返回一个简单的标量值或者一个标量和实体的结合体。

Double max = (Double) sess.createSQLQuery("select max(cat.weight) as maxWeight from cats cat")
        .addScalar("maxWeight", Hibernate.DOUBLE);
        .uniqueResult();

除此之外,你还可以在你的hbm文件中描述结果集映射信息,在查询中使用。

List cats = sess.createSQLQuery(
        "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
    )
    .setResultSetMapping("catAndKitten")
    .list();

16.2. 别名和属性引用

上面使用的{cat.*}标记是 "所有属性" 的简写.你可以显式地列出需要的字段,但是你必须让Hibernate 为每一个属性注入字段的别名.这些字段的站位符是以字段别名为前导,再加上属性名.在下面的例子里,我们从一个其他的表(cat_log) 中获取Cat对象,而非Cat对象原本在映射元数据中声明的表.注意我们甚至在where子句中也可以使用属性别名. 对于命名查询,{}语法并不是必需的.你可以在第 16.3 节 “命名SQL查询”得到更多的细节.

String sql = "select cat.originalId as {cat.id}, " +
    "cat.mateid as {cat.mate}, cat.sex as {cat.sex}, " +
    "cat.weight*10 as {cat.weight}, cat.name as {cat.name} " +
    "from cat_log cat where {cat.mate} = :catId"
    
List loggedCats = sess.createSQLQuery(sql)
    .addEntity("cat", Cat.class)
    .setLong("catId", catId)
    .list();

注意:如果你明确地列出了每个属性,你必须包含这个类它的子类的属性!

下表列出了使用别名注射参数的不同可能性。注意:下面结果中的别名只是示例,实用时每个别名需要唯一并且不同的名字。

表 16.1. 别名注射(alias injection names)

描述 语法 示例
 
简单属性 {[aliasname].[propertyname] A_NAME as {item.name}  
复合属性 {[aliasname].[componentname].[propertyname]} CURRENCY as {item.amount.currency}, VALUE as {item.amount.value}  
实体辨别器(Discriminator of an entity) {[aliasname].class} DISC as {item.class}  
实体的所有属性 {[aliasname].*} {item.*}  
集合键(collection key) {[aliasname].key} ORGID as {coll.key}  
集合id {[aliasname].id} EMPID as {coll.id}  
集合元素 {[aliasname].element} XID as {coll.element}  
集合元素的属性 {[aliasname].element.[propertyname]} NAME as {coll.element.name}  
集合元素的所有属性 {[aliasname].element.*} {coll.element.*}  
集合的所有属性 {[aliasname].*} {coll.*}  

16.3. 命名SQL查询

可以在映射文档中定义查询的名字,然后就可以象调用一个命名的HQL查询一样直接调用命名SQL查询.在这种情况下,我们 需要调用addEntity()方法.

<sql-query name="persons">
    <return alias="person" class="eg.Person"/>
    SELECT person.NAME AS {person.name},
           person.AGE AS {person.age},
           person.SEX AS {person.sex}
    FROM PERSON person
    WHERE person.NAME LIKE :namePattern
</sql-query>
List people = sess.getNamedQuery("persons")
    .setString("namePattern", namePattern)
    .setMaxResults(50)
    .list();

<return-join><load-collection> 元素是用来连接关联以及将查询定义为预先初始化各个集合的。

<sql-query name="personsWith">
    <return alias="person" class="eg.Person"/>
    <return-join alias="address" property="person.mailingAddress"/>
    SELECT person.NAME AS {person.name},
           person.AGE AS {person.age},
           person.SEX AS {person.sex},
           adddress.STREET AS {address.street},
           adddress.CITY AS {address.city},
           adddress.STATE AS {address.state},
           adddress.ZIP AS {address.zip}
    FROM PERSON person
    JOIN ADDRESS adddress
        ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
    WHERE person.NAME LIKE :namePattern
</sql-query>

一个命名查询可能会返回一个标量值.你必须使用<return-scalar>元素来指定字段的别名和 Hibernate类型

<sql-query name="mySqlQuery">
    <return-scalar column="name" type="string"/>
    <return-scalar column="age" type="long"/>
    SELECT p.NAME AS name,
           p.AGE AS age,
    FROM PERSON p WHERE p.NAME LIKE 'Hiber%'
</sql-query>

你可以把结果集映射的信息放在外部的<resultset>元素中,这样就可以在多个命名查询间,或者通过setResultSetMapping()API来访问。(此处原文即存疑。原文为:You can externalize the resultset mapping informations in a <resultset> element to either reuse them accross several named queries or through the setResultSetMapping() API.)

<resultset name="personAddress">
    <return alias="person" class="eg.Person"/>
    <return-join alias="address" property="person.mailingAddress"/>
</resultset>

<sql-query name="personsWith" resultset-ref="personAddress">
    SELECT person.NAME AS {person.name},
           person.AGE AS {person.age},
           person.SEX AS {person.sex},
           adddress.STREET AS {address.street},
           adddress.CITY AS {address.city},
           adddress.STATE AS {address.state},
           adddress.ZIP AS {address.zip}
    FROM PERSON person
    JOIN ADDRESS adddress
        ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
    WHERE person.NAME LIKE :namePattern
</sql-query>

16.3.1. 使用return-property来明确地指定字段/别名

使用<return-property>你可以明确的告诉Hibernate使用哪些字段别名,这取代了使用{}-语法 来让Hibernate注入它自己的别名.

<sql-query name="mySqlQuery">
    <return alias="person" class="eg.Person">
      <return-property name="name" column="myName"/>
      <return-property name="age" column="myAge"/>
      <return-property name="sex" column="mySex"/>
    </return>
    SELECT person.NAME AS myName,
           person.AGE AS myAge,
           person.SEX AS mySex,
    FROM PERSON person WHERE person.NAME LIKE :name
</sql-query>
<return-property>也可用于多个字段,它解决了使用{}-语法不能细粒度控制多个字段的限制
<sql-query name="organizationCurrentEmployments">
            <return alias="emp" class="Employment">            
             <return-property name="salary"> 
               <return-column name="VALUE"/>
               <return-column name="CURRENCY"/>            
             </return-property>
             <return-property name="endDate" column="myEndDate"/>
            </return>
            SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer}, 
            STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
            REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY
            FROM EMPLOYMENT
            WHERE EMPLOYER = :id AND ENDDATE IS NULL
            ORDER BY STARTDATE ASC
</sql-query>

注意在这个例子中,我们使用了<return-property>结合{}的注入语法. 允许用户来选择如何引用字段以及属性.

如果你映射一个识别器(discriminator),你必须使用<return-discriminator> 来指定识别器字段

16.3.2. 使用存储过程来查询

Hibernate 3引入了对存储过程查询(stored procedure)和函数(function)的支持.以下的说明中,这二者一般都适用。 存储过程/函数必须返回一个结果集,作为Hibernate能够使用的第一个外部参数. 下面是一个Oracle9和更高版本的存储过程例子.

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;

在Hibernate里要要使用这个查询,你需要通过命名查询来映射它.

<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>

注意存储过程当前仅仅返回标量和实体.现在不支持<return-join><load-collection>

16.3.2.1. 使用存储过程的规则和限制

为了在Hibernate中使用存储过程,你必须遵循一些规则.不遵循这些规则的存储过程将不可用.如果你仍然想要使用他们, 你必须通过session.connection()来执行他们.这些规则针对于不同的数据库.因为数据库 提供商有各种不同的存储过程语法和语义.

对存储过程进行的查询无法使用setFirstResult()/setMaxResults()进行分页。

建议采用的调用方式是标准SQL92: { ? = call functionName(<parameters>) } 或者 { ? = call procedureName(<parameters>}.原生调用语法不被支持。

对于Oracle有如下规则:

  • 函数必须返回一个结果集。存储过程的第一个参数必须是OUT,它返回一个结果集。这是通过Oracle 9或10的SYS_REFCURSOR类型来完成的。在Oracle中你需要定义一个REF CURSOR类型,参见Oracle的手册。

对于Sybase或者MS SQL server有如下规则:

  • 存储过程必须返回一个结果集。.注意这些servers可能返回多个结果集以及更新的数目.Hibernate将取出第一条结果集作为它的返回值, 其他将被丢弃。

  • 如果你能够在存储过程里设定SET NOCOUNT ON,这可能会效率更高,但这不是必需的。

16.4. 定制SQL用来create,update和delete

Hibernate3能够使用定制的SQL语句来执行create,update和delete操作。在Hibernate中,持久化的类和集合已经 包含了一套配置期产生的语句(insertsql, deletesql, updatesql等等),这些映射标记 <sql-insert>, <sql-delete>, and <sql-update>重载了 这些语句。

<class name="Person">
    <id name="id">
        <generator class="increment"/>
    </id>
    <property name="name" not-null="true"/>
    <sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert>
    <sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update>
    <sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
</class>

这些SQL直接在你的数据库里执行,所以你可以自由的使用你喜欢的任意语法。但如果你使用数据库特定的语法, 这当然会降低你映射的可移植性。

如果设定callable,则能够支持存储过程了。

<class name="Person">
    <id name="id">
        <generator class="increment"/>
    </id>
    <property name="name" not-null="true"/>
    <sql-insert callable="true">{call createPerson (?, ?)}</sql-insert>
    <sql-delete callable="true">{? = call deletePerson (?)}</sql-delete>
    <sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
</class>

参数的位置顺序是非常重要的,他们必须和Hibernate所期待的顺序相同。

你能够通过设定日志调试级别为org.hiberante.persister.entity,来查看Hibernate所期待的顺序。在这个级别下, Hibernate将会打印出create,update和delete实体的静态SQL。(如果想看到预计的顺序。记得不要将定制SQL包含在映射文件里, 因为他们会重载Hibernate生成的静态SQL。)

在大多数情况下(最好这么做),存储过程需要返回插入/更新/删除的行数,因为Hibernate对语句的成功执行有些运行时的检查。 Hibernate常会把进行CUD操作的语句的第一个参数注册为一个数值型输出参数。

CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
    RETURN NUMBER IS
BEGIN

    update PERSON
    set
        NAME = uname,
    where
        ID = uid;

    return SQL%ROWCOUNT;

END updatePerson;

16.5. 定制装载SQL

你可能需要声明你自己的SQL(或HQL)来装载实体

<sql-query name="person">
    <return alias="pers" class="Person" lock-mode="upgrade"/>
    SELECT NAME AS {pers.name}, ID AS {pers.id}
    FROM PERSON
    WHERE ID=?
    FOR UPDATE
</sql-query>

这只是一个前面讨论过的命名查询声明,你可以在类映射里引用这个命名查询。

<class name="Person">
    <id name="id">
        <generator class="increment"/>
    </id>
    <property name="name" not-null="true"/>
    <loader query-ref="person"/>
</class>

这也可以用于存储过程

你甚至可以定一个用于集合装载的查询:

<set name="employments" inverse="true">
    <key/>
    <one-to-many class="Employment"/>
    <loader query-ref="employments"/>
</set>
<sql-query name="employments">
    <load-collection alias="emp" role="Person.employments"/>
    SELECT {emp.*}
    FROM EMPLOYMENT emp
    WHERE EMPLOYER = :id
    ORDER BY STARTDATE ASC, EMPLOYEE ASC
</sql-query>

你甚至还可以定义一个实体装载器,它通过连接抓取装载一个集合:

<sql-query name="person">
    <return alias="pers" class="Person"/>
    <return-join alias="emp" property="pers.employments"/>
    SELECT NAME AS {pers.*}, {emp.*}
    FROM PERSON pers
    LEFT OUTER JOIN EMPLOYMENT emp
        ON pers.ID = emp.PERSON_ID
    WHERE ID=?
</sql-query>
分享到:
评论

相关推荐

    Hibernate之原生Native SQL查询

    然而,尽管Hibernate提供了强大的HQL(Hibernate Query Language)和Criteria API,但在处理某些特定的、复杂的SQL查询时,可能无法满足需求,这时就需要用到“原生的Native SQL查询”。 Native SQL查询允许我们...

    Native SQL查询 (使用SQLQuery).doc

    Native SQL 查询 (使用 SQLQuery) 在 Hibernate 中,使用 SQLQuery 可以执行 Native SQL 查询,控制查询的执行是通过 SQLQuery 接口进行的,通过执行 Session.createSQLQuery() 获取这个接口。下面将详细介绍如何...

    Native-SQL查询 (1).ppt

    本节主要探讨的是如何在Hibernate框架中使用Native SQL查询,它允许开发者直接执行原生的SQL语句,绕过HQL(Hibernate Query Language)进行更灵活的数据操作。 Hibernate是一个流行的Java对象关系映射(ORM)框架...

    hibernate3中通过nativesql或取部分字段并映射为具体对象的实现

    本篇文章将深入探讨在Hibernate3中如何通过Native SQL查询部分字段,并将其映射到具体的Java对象上。这种方式在处理一些特定的、效率较高的SQL查询时非常有用。 首先,我们需要理解Hibernate中的`SQLQuery`接口,这...

    Microsoft SQL Server Native Client (SQL Native Client)

    Microsoft SQL Server Native Client (SQL Native Client) 是一个同时包含 SQL OLE DB 访问接口和 SQL ODBC 驱动程序的动态链接库 (DLL)。它对使用本机代码 API(ODBC、OLE DB 和 ADO)连接到 Microsoft SQL Server ...

    SQL server Native Client 10.0

    SQL Server Native Client 10.0 是微软推出的一款专门用于与SQL Server 2008及后续版本交互的客户端库,它集成了ODBC(Open Database Connectivity)和OLE DB(Object Linking and Embedding, Database)接口。...

    SQL Server Native Client 10.0

    在SQL Server 2012中,虽然主要推荐使用SQL Server Native Client 11.0,但为了兼容旧版本的SQL Server,如SQL Server 2000,仍然需要使用SQL Server Native Client 10.0。 **1. ODBC与OLE DB接口** - **ODBC**: ...

    SQL Server Native Client 10.0 驱动

    开发者可以通过ODBC的API调用来执行SQL查询、事务处理、游标操作等。 **OLE DB**: OLE DB是微软的另一种数据库访问技术,它比ODBC更底层,提供了更多的数据库访问功能。SQL Server Native Client 10.0 的OLE DB...

    sql server 2008 native client

    SQL Server 2008 Native Client是微软推出的一款用于与SQL Server进行数据交互的客户端库,它是SQL Server数据库引擎和应用程序之间的一个接口。这个库包含了ODBC(Open Database Connectivity)驱动程序和OLE DB...

    Microsoft SQL Server 2008 R2 SP1 Native Client

    Microsoft SQL Server 2008 Native Client (SQL Server Native Client) 是单一动态链接库 (DLL),其中包含 SQL OLE DB 提供者和 SQL ODBC 驱动程序。此链接库针对使用机器码 API (ODBC、OLE DB 和 ADO) 的应用程序...

    SQL Server Native Client 10.0.zip

    SQL Server Native Client 10.0 是微软针对SQL Server数据库管理系统推出的一款客户端接口,主要用于在Windows平台上连接和操作SQL Server 2008及其R2版本。这个压缩包"SQL Server Native Client 10.0.zip"包含了...

    SQL Server Native Client 11-sqlncli-11驱动

    SQL Server Native Client 11(简称sqlncli_11)是Microsoft开发的一款用于与SQL Server交互的客户端库,尤其适用于需要高性能数据访问的应用程序。它整合了ODBC(Open Database Connectivity)和OLE DB(Object ...

    SQL Server Native Client 客户端

    SQL Server Native Client(简称SQLNCLI)是微软推出的一个专门用于与SQL Server交互的客户端库,它是SQL Server 2005引入的新特性,旨在提供更高效、更安全的数据库访问方式。SQLNCLI集成了ODBC(Open Database ...

    SQL Server Native Client大全(官网下载整理9,10,11)

    - **高性能**:相比早期的数据库访问技术,SQL Server Native Client优化了性能,减少了网络传输,提升了查询速度。 - **高级数据类型支持**:支持SQL Server特有的数据类型,如XML、大型对象(LOB)等。 - **...

    Microsoft SQL Server 2005 Native Client

    **Microsoft SQL Server 2005 Native Client** 是一个专门设计用于与Microsoft SQL Server进行高效交互的数据访问组件。它是SQL Server 2005引入的一个重要特性,为开发者提供了更强大的功能和性能优化,同时也兼容...

    SQL Server 2008 Native Client(32&64)

    Microsoft sql server 2008 Native Client (SQL Server Native Client) 是一个同时包含 SQL OLE DB 访问接口和 SQL ODBC 驱动程序的动态链接库 (DLL)。它对使用本机代码 API(ODBC、OLE DB 和 ADO)连接 Microsoft ...

    SQL Server Native Client 9.0~11.0(32位和64位)

    SQL Server Native Client是微软开发的一款专门用于与SQL Server交互的客户端库,支持多种数据库访问接口,包括ODBC(Open Database Connectivity)和OLE DB(Object Linking and Embedding, Database)。...

    SQL Server 2012 Native Client.rar

    在SQL Server Native Client中,ODBC驱动程序提供了用于执行SQL查询、事务处理等功能的接口。 - **OLE DB**:是微软特定的数据库访问技术,它允许开发者直接访问数据库对象,如表、视图和存储过程,提供更底层的...

    SQl Server 2008 Native Client 10.0

    又需要Native Client支持 SQL Server 2008 的朋友可以下载!

Global site tag (gtag.js) - Google Analytics