Oracle采用SQLQuery 在Hibernate中采取sql语句

本着原生SQL查询执行之决定是经过SQLQuery接口进行的,通过推行Session.createSQLQuery()得到这接口。下面来描述如何采取是API进行询问。

1.标量查询(Scalar queries)

太基本的SQL查询就是抱一个标量(数值)的列表。

sess.createSQLQuery("SELECT * FROM CATS").list();
sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list();

它们都将返回一个Object数组(Object[])组成的List,数组每个元素还是CATS表的一个字段值。Hibernate会使用ResultSetMetadata来判定返回的标量值的其实顺序和品种。

只要要是避过多的行使ResultSetMetadata,或者只是为更加扎眼的指定返回值,可以行使addScalar()

sess.createSQLQuery("SELECT * FROM CATS").addScalar("ID", Hibernate.LONG).addScalar("NAME", Hibernate.STRING).addScalar("BIRTHDATE", Hibernate.DATE);

夫查询指定了:

  • SQL查询字符串

  • 倘若回来的字段和类别

它依旧会回去Object数组,但是此时不再利用ResultSetMetdata,而是明确的将ID,NAME和BIRTHDATE按照Long,String和Short类型从resultset中取出。同时,也指明了就是query是采取*来询问的,可能获取超过列有之立即三只字段,也不过会回来就三独字段。

对合要么局部的标量值不装类型信息也是可的。

sess.createSQLQuery("SELECT * FROM CATS") .addScalar("ID", Hibernate.LONG) .addScalar("NAME") .addScalar("BIRTHDATE");

大多就与前边一个查询同一,只是这以ResultSetMetaData来支配NAME和BIRTHDATE的种类,而ID的类别是明确指出的。

关于从ResultSetMetaData返回的java.sql.Types是何等映射到Hibernate类型,是出于方言(Dialect)控制的。假若有指定的品种没有受射,或者无是公所预期的色,你可经Dialet的registerHibernateType调用自行定义。

2.实体查询(Entity queries)

上面的查询都是回标量值的,也便是自从resultset中归的“裸”数据。下面展示如何通过addEntity()为原生查询返回实体对象。

sess.createSQLQuery("SELECT * FROM CATS").addEntity(Cat.class); 
sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").addEntity(Cat.class);

是查询指定:

  • SQL查询字符串

  • 若返回的实体

要Cat被射为持有ID,NAME和BIRTHDATE三只字段的类似,以上的片独查询都回来一个List,每个元素都是一个Cat实体。

倘实体在炫耀时起一个many-to-one的涉指向另外一个实体,在询问时得为回那个实体,否则会招产生一个”column
not
found”的数据库错误。这些附加的字段可以用*号来机关返回,但我们盼望或者判指明,看下面这有着对Dogmany-to-one的例子:

sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, DOG_ID FROM CATS").addEntity(Cat.class);

这般cat.getDog()就可知健康运作。

 


 

 

2.1. 拍卖涉及和集合类(Handling associations and collections)

通过提前抓取将Dog接连获得,而幸免初始化proxy带来的额外开销也是可能的。这是透过addJoin()法开展的,这个点子可以被你将关乎或者集合连接上。

sess.createSQLQuery("SELECT c.ID, NAME, BIRTHDATE, DOG_ID, D_ID, D_NAME FROM CATS c, DOGS d WHERE c.DOG_ID = d.D_ID").addEntity("cat", Cat.class).addJoin("cat.dog");

方是事例中,返回的Cat对象,其dog性为全初始化了,不再需要数据库的额外操作。注意,我们加了一个号(“cat”),以便指明join的靶子属性路径。通过平等的超前连接为堪作用被集合类,例如,假要Cat有一个对准Dog的如出一辙对大多涉及。

sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, D_ID, D_NAME, CAT_ID FROM CATS c, DOGS d WHERE c.ID = d.CAT_ID") .addEntity("cat", Cat.class) .addJoin("cat.dogs");

及此结束,我们相遇了天花板:若不对准SQL查询进行加强,这些早已是以Hibernate中以原生SQL查询所能完成的绝老或了。

脚的问题将面世:返回多个一律类型的实体怎么处置?或者默认的号/字段未敷又怎么惩罚?

2.1.1. 回去多个实体(Returning multiple entities)

暨目前为止,结果集字段名被如为与照耀文件被指定的底字段名是同的。假若SQL查询连接了大多单说明,同一个字段名可能于多独表中出现频,这即见面促成问题。

下面的查询中需要用字段别名注射(这个例子本身会败):

sess.createSQLQuery("SELECT c.*, m.* FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID") .addEntity("cat", Cat.class) .addEntity("mother", Cat.class);

其一查询的本意是要每行返回两个Cat实例,一个是cat,另一个凡是它的妈妈。但是坐她的字段名被映射为同一的,而且每当好几数据库被,返回的字段别名是“c.ID”,”c.NAME”这样的形式,而它同于投文件中之讳(”ID”和”NAME”)不配合,这就是会见造成破产。

脚的样式好缓解字段名重复:

sess.createSQLQuery("SELECT {cat.*}, {mother.*} FROM CATS c, CATS m WHERE c.MOTHER_ID = m.ID") .addEntity("cat", Cat.class) .addEntity("mother", Cat.class);

这个查询指明:

  • SQL查询语句,其中含有占各项附来让Hibernate注射字段别名

  • 查询返回的实业

上面运用的{cat.*}和{mother.*}标记是用作“所有属性”的简写形式出现的。当然你吗得以显著地摆出字段名,但当此事例里我们为Hibernate来啊每个属性注射SQL字段别名。字段别名的占用位符是属性名加上表别名之前缀。在下面的事例中,我们由另外一个发明(cat_log)中通过映射元数据被的指定获取Cat和它的妈妈。注意,要是我们愿,我们甚至好当where子句被采用属性别名。

String sql = "SELECT ID as {c.id}, NAME as {c.name}, " + "BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " + "FROM CAT_LOG c, CAT_LOG m WHERE {c.mother} = c.ID"; 
List loggedCats = sess.createSQLQuery(sql) .addEntity("cat", Cat.class) .addEntity("mother", Cat.class).list();

2.1.2. 号和属性引用(Alias and property references)

大多数景象下,都亟待者的性质注射,但以采取更错综复杂的投射,比如复合性、通过标识符构造继承树,以及集合类等等情况下,也发一部分特地之号,来允许Hibernate注射合适的别名。

下表列有了用别名注射参数的两样可能性。注意:下面结果遭到的别名只是示例,实用时每个别名需要唯一同时不同的名。

表 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.*}

2.1.3. 归非受管实体(Returning non-managed entities)

得对原生sql
查询利用ResultTransformer。这会回去不深受Hibernate管理之实业。

sess.createSQLQuery("SELECT NAME, BIRTHDATE FROM CATS") .setResultTransformer(Transformers.aliasToBean(CatDTO.class))

其一查询指定:

  • SQL查询字符串

  • 结果转换器(result transformer)

上面的查询将会回来CatDTO的列表,它将被实例化并且将NAME和BIRTHDAY的值注射入对应之属性或者字段。

2.1.4. 甩卖继承(Handling inheritance)

原生SQL查询假若那查询结果实体是连续树被之一致有的,它必须含有基类和具有子类的具备属性。

2.1.5. 参数(Parameters)

原生查询支持位置参数和命名参数:

Query query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like ?").addEntity(Cat.class); 
List pusList = query.setString(0, "Pus%").list(); 
query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like :name").addEntity(Cat.class); 
List pusList = query.setString("name", "Pus%").list();

 

2.2. 命名SQL查询

可当炫耀文档中定义查询的名,然后便可以象调用一个命名的HQL查询同一一直调用命名SQL查询.在这种状况下,我们addEntity()方法.

<sql-query > 
  <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 > 
  <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 > 
  <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
<resultset>element to either reuse them accross several named
queries or through the setResultSetMapping() API.)

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

 

此外,你得于java代码中一直行使hbm文件被的结果集定义信息。

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

 

2.2.1. 以return-property来家喻户晓地指定字段/别名

使用<return-property>公可一目了然的语Hibernate使用什么字段别名,这代表了用{}-语法
来深受Hibernate注入其自己的别名.

<sql-query > 
  <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 >
  <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> 来指定识别器字段

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

2.2.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,这也许会见效率还强,但随即不是必备的。

 

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

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

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

 

2.4. 定制装载SQL

公恐怕要声明你协调的SQL(或HQL)来装实体

<sql-query> 
  <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> 
  <id name="id"> 
    <generator class="increment"/> 
  </id> 
  <property name="name" not-null="true"/> 
  <loader query-ref="person"/> 
</class>

顿时也可用来存储过程

卿居然足以一定一个用来汇装载的查询:

<set inverse="true"> 
  <key/> 
  <one-to-many class="Employment"/> 
  <loader query-ref="employments"/> 
</set>
<sql-query> 
  <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> 
  <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>

转自:http://www.cnblogs.com/ejllen/p/3704599.html

相关文章