hibernate对原生SQL查询的支持和控制是通过SQLQuery接口实现的,这种方式弥补了HQL、Criterion查询的不足,在操作和使用上往往更加的自由和灵活,如果使用得当,数据库操作的效率还会得到不同程度的提升。
Hibernate对原生 SQL查询的支持和控制是通过SQLQuery接口实现的。通过Session接口,我们能够很方便的创建一个SQLQuery(SQLQuery是一个 接口,在Hibernate4.2.2之前,默认返回的是SQLQuery的实现类——SQLQueryImpl对象,在下文中出现的SQLQuery如 非注明,都是指该子类)对象来进行原生SQL查询:
session.createSQLQuery(String sql);
SQLQuery实现了Query接口,因此你可以使用Query接口中提供的API来获取数据。
最简单的示例
//获取所有查询结果
session.createSQLQuery("select * from note").list();
//仅获取第一条结果
session.createSQLQuery("select * from note where id = 1").uniqueResult();
使用预处理SQL
预 处理SQL的好处自然不必多说,除了众所周知的能够防止SQL注入攻击外,还能够在一定程度上提高SQL的查询效率。SQLQuery提供了众多的接口来 分别设置不同类型的参数,诸如setBigDecimal、setBinary、setDouble等,详参SQLQuery的JavaDoc,此处不再 赘述。这里仅重点说一下通用的SQL参数设置接口setParameter。
如下代码示范了如何使用SQLQuery执行预处理SQL:
SQLQuery query = session.createSQLQuery("select * from note where id = ?");
//设置第一个参数的值为12,即查询ID=12的note
query.setParameter(0, 12);
List list = query.list();
...
这里需要注明一点,无论是通过不同类型参数的设置接口来设置SQL参数,还是通过setParameter来设置参数,下标都是从0开始的,而不是从1开始的!
使用自定义的结果转换器处理查询结果
SQLQuery 接口预留了setResultTransformer接口以实现使用用户自定义的ResultTransformer结果集转换器处理查询结果。 ResultTransformer接口非常简单,只有两个方法,分别用来转换单行数据和所有结果数据。经过自定义ResultTransformer生 成的实体,并未加入Session,因此是非受管实体。
如下代码,示范了如何将单行数据装入LinkedHashMap对象中:
query.setResultTransformer(new ResultTransformer() {
@Override
public Object transformTuple(Object[] values, String[] columns) {
Map<String, Object> map = new LinkedHashMap<String, Object>(1);
int i = 0;
for(String column : columns){
map.put(column, values[i++]);
}
return map;
}
@Override
public List transformList(List list) {
return list;
}
});
如果不设置自定义的ResultTransformer转换器,则Hibernate将每行返回结果的数据按照结果列的顺序装入Object数组中。
这里介绍一个工具类:Transformers,它提供了一些常用的转换器,能够帮助我们快速转换结果集,如Transformers.aliasToBean(Note.class)能够将查询结果依别名注入到Note实体中。
使用标量
使用SQLQuery执行原生SQL时,Hibernate会使用ResultSetMetadata来判定返回的标量值的实际顺序和类型。如果要避免过多的使用ResultSetMetadata,或者只是为了更加明确的指名返回值,可以使用addScalar()。
session.createSQLQuery("select * from note where id = 1")
.addScalar("id", LongType.INSTANCE)
.addScalar("name", StringType.INSTANCE)
.addScalar("createtime", DateType.INSTANCE);
这个查询指定了SQL查询字 符串,要返回的字段和类型.它仍然会返回Object数组,但是此时不再使用ResultSetMetdata,而是明确的将id,name和 createtime按照Long, String和Date类型从resultset中取出。同时,也指明了就算query是使用*来查询的,可能获得超过列出的这三个字段,也仅仅会返回这 三个字段。
对全部或者部分的标量值不设置类型信息也是可以的:
session.createSQLQuery("select * from note where id = 1")
.addScalar("id")
.addScalar("name")
.addScalar("createtime", DateType.INSTANCE);
没有被指定类型的字段将仍然使用ResultSetMetdata获取其类型。注意,字段不区分大小写,同时不能够指定不存在的字段!
关 于从ResultSetMetaData返回的java.sql.Types是如何映射到Hibernate类型,是由方言(Dialect)控制的。假 若某个指定的类型没有被映射,或者不是你所预期的类型,你可以通过Dialet的registerHibernateType调用自行定义。
如果仅指定了一个scalar,那么...
Date createTime = (Date)session.createSQLQuery("select * from note where id = 1")
.addScalar("createtime", DateType.INSTANCE)
.uniqueResult();
如果我们的SQL语句使用了聚合函数,如count、max、min、avg等,且返回结果仅一个字段,那么Hibernate提供的这种提取标量结果的方式就非常便捷了。
实体查询
上面的查询都是返回标量值的,也就是从resultset中返回的“裸”数据。下面展示如何通过addEntity()让原生查询返回实体对象。
session.createSQLQuery("select * from note where id = 1").addEntity(Note.class);
session.createSQLQuery("select id,name,createtime from note where id = 1").addEntity(Note.class);
这个查询指定SQL查询字符串,要返回的实体。假设Note被映射为拥有id,name和createtime三个字段的类,以上的两个查询都返回一个List,每个元素都是一个Note实体。
假 若实体在映射时有一个many-to-one的关联指向另外一个实体,在查询时必须也返回那个实体,否则会导致发生一个"column not found"的数据库错误。这些附加的字段可以使用*标注来自动返回,但我们希望还是明确指明,看下面这个具有指向Dog的many-to-one的例 子:
session.createSQLQuery("select id,note,createtime,author from note where id = ?").addEntity(Note.class);
author字段即为Note实体和Author实体的关联字段,只需在查询时得到该字段的值,Hibernate即可使用该值找到对应的关联实体。如上例中,note.getAuthor()即可返回当前Note所属的Author对象。
处理关联和集合类
通过提前抓取将Author连接获得,而避免初始化proxy带来的额外开销也是可能的。这是通过addJoin()方法进行的,这个方法可以让你将关联或集合连接进来。
session.createSQLQuery("select {note.*}, {author.*} from note note, user author where note.author = author.id")
.addEntity("note", Note.class)
.addJoin("author", "note.author");
上面的例子是多对一的关联查询,反过来做一对多的关联查询也是可以的。如下的例子中,author.notes表示该用户发表的所有日记(Note),Set集合类型:
session.createSQLQuery("select {author.*},{note.*} from note note, user author where author.id = ? and note.author = author.id")
.addEntity("author", User.class)
.addJoin("note", "author.notes");
注意:join查询会在每行返回多个实体对象,处理时需要注意。
别名和属性引用
假若SQL查询连接了多个表,同一个字段名可能在多个表中出现多次,这会导致SQL错误。不过在我们可以通过使用占位符来完美地解决这一问题。
其实在上例中已经用到了占位符:
session.createSQLQuery("select {note.*}, {author.*} from note note, user author where note.author = author.id")
.addEntity("note", Note.class)
.addJoin("author", "note.author");
这个查询指明SQL查询语句,其中包含占位附来让Hibernate注入字段别名,查询并返回的实体。
上面使用的{note.*}和{author.*}标记是作为“所有属性”的简写形式出现的,当然你也可以明确地罗列出字段名。但如下的范例代码中我们让Hibernate来为每个属性注入SQL字段别名,字段别名的占位符是表别名 + . + 属性名。
注意:属性名区分大小写,而且不能够在where子句中使用占位符。
SQLQuery query = session.createSQLQuery("select note.id as {note.id},note as {note.note},createtime as {note.createTime},author as {note.author}, {author.*} from note, user author where note.id = ? and note.author = author.id");
query.addEntity("note", Note.class);
query.addJoin("author", "note.author");
大多数情况下,上面的别名注入方式可以满足需要,但在使用更加复杂的映射,比如复合属性、通过标识符构造继承树,以及集合类等等情况下,则需要更加复杂的别名注入方式。
下表列出了使用别名注射参数的不同方式:
别名注入(alias injection names) 描述 语法 示例
简单属性 {[aliasname].[propertyname] A_NAME as {item.name}
复合属性 {[aliasname].[componentname].[propertyname]} CURRENCY as {item.amount.currency}, VALUE as {item.amount.value}
实体辨别器 {[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.*}
在hbm文件中描述结果集映射信息,并在查询中使用
对于一些复杂的结果集映射,往往需要像MyBatis那样在文件中手动配置好,然后在程序中使用。幸运的是Hibernate也提供了类似的功能,你可以使用自己配置的结果集映射来处理返回的结果集数据:
SQLQuery query = session.createSQLQuery("select note.id as {note.id},note as {note.note},createtime as {note.createTime},author as {note.author}, {author.*} from note, user author where note.id = ? and note.author = author.id");
//使用在hbm文件中配置的自定义结果集映射
query.setResultSetMapping("noteAnduthor");
query.list();
执行更新操作
使用SQLQuery执行数据库更新操作比较容易,除了像查询时那样需要指定SQL语句(如有需要还需设置SQL参数)外,仅需调用executeUpdate()方法,即可提交更新操作。代码如下所示:
session.createSQLQuery("update createtime = ? from note where note.id = ?");
query.setDate(0, new Date());
query.setLong(1, 1L);
query.executeUpdate();
executeUpdate方法的返回结果为改变的数据库记录的行数。
转载地址: http://www.yshjava.cn/post/543.html
分享到:
相关推荐
"hibernate执行原生sql语句" Hibernate 是一种流行的 ORM(Object-Relational Mapping)框架,用于将 Java 对象映射到关系数据库中。然而,在一些情况下,我们需要直接执行原生 SQL 语句,而不是使用 Hibernate 的...
本文将针对给定代码片段中的核心知识点——如何在Hibernate中使用原生SQL而非HQL进行详细解析。 #### 一、为什么要使用原生SQL? 虽然HQL是Hibernate提供的面向对象的语言,能够方便地映射到Java对象,但在某些...
在Java的持久化框架Hibernate中,执行原生SQL(Native SQL)是常见需求,尤其是在处理特定数据库特性或者优化性能时。本篇文章将详细介绍在Hibernate中执行原生SQL的几种方式,以及它们各自的适用场景和优缺点。 1....
描述中提到"自己封装了原生sql的处理,模仿mybatis使用",这意味着开发者在项目中创建了一个类似MyBatis的简单SQL解析器。MyBatis是一个轻量级的持久层框架,它允许开发者编写原生的SQL语句并将其与Java代码绑定。...
Native SQL查询允许我们直接使用SQL语句来与数据库交互,不受HQL的限制,可以充分利用SQL的功能,如存储过程、自定义函数、复杂的联接和子查询等。这种方式尤其适用于那些对数据库性能有极高要求或者对数据库结构有...
标题 "Hibernat使用原生的SQL" 涉及的是在Java开发中如何利用Hibernate框架执行自定义的SQL语句。Hibernate是一个流行的...为了进一步学习,建议阅读该文档,进行实际的编码练习,以加深对Hibernate原生SQL使用的理解。
在开发和调试基于Hibernate的Java应用时,有时我们需要获取到SQL语句的完整形式,而不仅仅是Hibernate默认输出的参数化形式。在这种情况下,P6Spy是一个非常有用的工具。P6Spy是一个开源的JDBC代理库,它允许我们...
添加了一条基础的SQL语句,其中`Tuser`是数据库中的表名,`t`是别名,`where 1=1`是一个常用的技巧,可以确保后面的条件能够正常拼接到SQL语句中。 4. **根据条件添加额外的SQL子句**: ```java if (name != ...
首先,本地SQL查询(Native SQL)是指直接在Hibernate中使用原生的SQL语句进行查询,而不是使用HQL(Hibernate Query Language)。这允许开发者充分利用SQL的功能,比如进行复杂的统计计算或者处理特定数据库的特性...
本文将深入探讨Hibernate中的缓存机制以及如何使用原生SQL语句。 缓存是提升应用程序性能的关键因素,特别是对于频繁访问数据库的应用。在Hibernate中,缓存分为三个层次: 1. 第一级缓存:这是SessionFactory创建...
这里创建的SQLQuery对象允许我们执行任意的SQL语句,而不是局限于Hibernate的HQL查询语言。 二、设置查询参数 设置查询参数可以通过setParameter方法完成,它接受两个参数:一个是参数的索引(从0开始),另一个是...
使用本地sql语句查询后,无需再使用Object对查询结果进行强制转换,而是直接将查询结果放到实体Bean里了。 PS: 其实只有一版,这里只所以叫最终版是因为该附件我上传了好几天传不上去,到最后报告说‘资源已经存在...
对于更复杂的SQL操作,可能需要使用原生的SQL语句。这个方法接收一个SQL字符串,通过Session获取数据库连接,创建PreparedStatement,执行查询,处理结果集,将其转换为ArrayList并返回。注意,这种方法需要手动处理...
- **函数或方法**:在编程语言中创建函数或方法,如在Python中使用def定义函数,Java中使用public void方法,将SQL语句作为参数传递,返回查询结果。 - **存储过程**:在数据库级别进行封装,创建存储过程,将一系列...
在 Hibernate 中,可以通过以下步骤执行原生 SQL 语句: 1. **创建 Session**:首先需要创建一个 `SessionFactory` 对象,然后通过该对象打开一个 `Session` 实例。 ```java Configuration config = new ...
Hibernate 的 createSQLQuery 是 Hibernate 框架中的一种强大且灵活的查询机制,它允许开发者使用原生 SQL 语句来查询数据库。下面是 createSQLQuery 的几种常见用法: 一、简单的 SQLQuery 在最简单的情况下,...
为了显示查询SQL,Hibernate 提供了`hibernatetool`,可以生成SQL脚本,或者通过配置`logging.level.org.hibernate.SQL`来打印SQL语句。此外,Hibernate的日志系统支持JDK Logging、Log4j 和 SLF4J。 **显示查询SQL...
SQL语句的编写质量直接影响到数据库的性能和维护性。当SQL语句变得复杂时,保持其整洁、易读就显得尤为重要。为了提升代码的可读性和可维护性,通常会使用SQL格式化工具对查询进行美化。本文将详细讲解一个基于C#...
MySQL 原生语句中 save 的写法汇总 在 MySQL 中,save 操作是经常遇到的场景,特别是在 UPDATE 和 INSERT 操作中。使用 Hibernate 可以使用 saveOrUpdate 方法,但是使用原生 SQL 语句时,该如何实现 save 操作呢?...
原生SQL查询允许开发者直接执行SQL语句,而HQL则是面向对象的查询语言,类似于SQL但更接近于Java。 4. 封装SQL查询结果为对象: - `Session`接口:执行SQL查询的主要入口点,它是Hibernate的核心接口,提供了打开...