使用Hibernate SQLQuery(转)

原文地址:http://itindex.net/detail/51776-hibernate-sqlquery-sql,重新排了一下版

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(){
        @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,newDate()); 
query.setLong(1,1L); 
query.executeUpdate();

 

executeUpdate方法的归来结果为转移的数据库记录的行数。

 

网站地图xml地图