使用Hibernate SQLQuery执行原生SQL

标签: hibernate sqlquery sql | 发表时间:2014-11-17 19:46 | 作者:coffeehot
出处:http://www.iteye.com
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(newResultTransformer(){@OverridepublicObject transformTuple(Object[] values,String[] columns){Map<String,Object> map =newLinkedHashMap<String,Object>(1);int i =0;for(String column : columns){ map.put(column, values[i++]);}return map;}@OverridepublicList 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,newDate()); query.setLong(1,1L); query.executeUpdate();

 

executeUpdate方法的返回结果为改变的数据库记录的行数。


转载地址: http://www.yshjava.cn/post/543.html



已有 0 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [hibernate sqlquery sql] 推荐:

使用Hibernate SQLQuery执行原生SQL

- - 企业架构 - ITeye博客
Hibernate对原生SQL查询的支持和控制是通过SQLQuery接口实现的,这种方式弥补了HQL、Criterion查询的不足,在操作和使用上往往更加的自由和灵活,如果使用得当,数据库操作的效率还会得到不同程度的提升. Hibernate对原生 SQL查询的支持和控制是通过SQLQuery接口实现的.

Hibernate SQL查询 addScalar()或addEntity()

- - SQL - 编程语言 - ITeye博客
Hibernate除了支持HQL查询外,还支持原生SQL查询.          对原生SQL查询执行的控制是通过SQLQuery接口进行的,通过执行Session.createSQLQuery()获取这个接口. 该接口是Query接口的子接口.          执行SQL查询步骤如下:.          1、获取Hibernate Session对象.

使用Hibernate+MySql+native SQL的BUG,以及解决办法

- - 互联网 - ITeye博客
使用Hibernate+MySql+native SQL的BUG,以及解决办法. 本来是mssql+hibernate+native SQL 应用的很和谐. 但是到了把mssql换成mysql,就出了错(同样的数据结构和数据). 看到最后Caused by: java.sql.SQLException:.

Hibernate面试题

- - ITeye博客
什么是Hibernate的并发机制. Hibernate并发机制:. a、Hibernate的Session对象是非线程安全的,对于单个请求,单个会话,单个的工作单元(即单个事务,单个线程),它通常只使用一次,. 如果一个Session 实例允许共享的话,那些支持并发运行的,例如Http request,session beans将会导致出现资源争用.

Hibernate Lazy属性

- - 博客园_首页
  Hibernate 的延迟加载(lazy load)是一个被广泛使用的技术. 这种延迟加载保证了应用只有在需要时才去数据库中抓取相应的记录. 通过延迟加载技术可以避免过多、过早地加载数据表里的数据,从而降低应用的内存开销. Hibernate 的延迟加载本质上就是代理模式的应用,当程序通过 Hibernate 装载一个实体时,默认情况下,Hibernate 并不会立即抓取它的集合属性、关联实体所以对应的记录,而是通过生成一个代理来表示这些集合属性、关联实体,这就是代理模式应用带来的优势.

Hibernate 缓存

- - ITeye博客
1数据缓存:(date caching) 是一种将数据暂时存于内存缓存去中的技术,缓存通常是影响系统性能的关键因素. 2.ORM的数据缓存策略有3中.   1.事务级缓存:  分为 数据库事务和 应用级事务,是基于Session的生命周期的实现,每个session都会在内部维持一个数据缓存, 随session的创建和消亡.

hibernate优化

- - 开源软件 - ITeye博客
原文 http://developer.51cto.com/art/200906/129539.htm. 文章分为十三个小块儿对Hibernate性能优化技巧进行总结性分析,分析如下:. 一、在处理大数据量时,会有大量的数据缓冲保存在Session的一级缓存中,这缓存大太时会严重显示性能,所以在使用Hibernate处理大数据量的,可以使用session.

JPA & Hibernate 注解

- - CSDN博客编程语言推荐文章
必须,name为可选,对应数据库中一的个表 . 可选,通常和@Entity配合使用,只能标注在实体的class定义处,表示实体对应的数据库表的信息 . name:可选,表示表的名称.默认地,表名和实体名称一致,只有在不一致的情况下才需要指定表名 . catalog:可选,表示Catalog名称,默认为Catalog(""). .

hibernate 大对象类型的hibernate映射

- - CSDN博客推荐文章
在 Java 中, java.lang.String 可用于表示长字符串(长度超过 255), 字节数组 byte[] 可用于存放图片或文件的二进制数据. 此外, 在 JDBC API 中还提供了 java.sql.Clob 和 java.sql.Blob 类型, 它们分别和标准 SQL 中的 CLOB 和 BLOB 类型对应.

JBoss发布Hibernate 4.0

- - InfoQ cn
近日, JBoss发布了流行的对象/关系(O/R)映射框架 Hibernate. Hibernate 4主要的新特性如下所示:. 引入了“Services”API. 提供了更棒的日志,支持 i18n与消息编码(通过JBoss Logging而非 slf4j). 为 OSGi支持做好了准备.