使用Hibernate SQLQuery执行原生SQL
对原生SQL查询的支持和控制是通过接口实现的。通过接口,我们能够很方便的创建一个(是一个接口,在.2.2之前,默认返回的是的实现类——对象,在下文中出现的如非注明,都是指该子类)对象来进行原生SQL查询:
session.createSQLQuery(String sql);
实现了Query接口,因此你可以使用Query接口中提供的API来获取数据。
最简单的示例
//获取所有查询结果session.createSQLQuery("select * from note").list();//仅获取第一条结果session.createSQLQuery("select * from note where id = 1").uniqueResult();
使用预处理SQL
预处理SQL的好处自然不必多说,除了众所周知的能够防止SQL注入攻击外,还能够在一定程度上提高SQL的查询效率。提供了众多的接口来分别设置不同类型的参数,诸如、、等,详参的,此处不再赘述。这里仅重点说一下通用的SQL参数设置接口。
如下代码示范了如何使用执行预处理SQL:
SQLQuery query = session.createSQLQuery("select * from note where id = ?");//设置第一个参数的值为12,即查询ID=12的notequery.setParameter(0, 12);List list = query.list();...
这里需要注明一点,无论是通过不同类型参数的设置接口来设置SQL参数,还是通过来设置参数,下标都是从0开始的,而不是从1开始的!
使用自定义的结果转换器处理查询结果
接口预留了接口以实现使用用户自定义的结果集转换器处理查询结果。接口非常简单,只有两个方法,分别用来转换单行数据和所有结果数据。经过自定义生成的实体,并未加入,因此是非受管实体。
如下代码,示范了如何将单行数据装入对象中:
query.setResultTransformer(new ResultTransformer() { @Override public Object transformTuple(Object[] values, String[] columns) { Map map = new LinkedHashMap(1); int i = 0; for(String column : columns){ map.put(column, values[i++]); } return map; } @Override public List transformList(List list) { return list; }});
如果不设置自定义的转换器,则将每行返回结果的数据按照结果列的顺序装入数组中。
当然,也可以直接指定默认的MAP转换规则:
query.(
.);
这里介绍一个工具类:,它提供了一些常用的转换器,能够帮助我们快速转换结果集,如.(Note.class)能够将查询结果依别名注入到Note实体中。
使用标量
使用执行原生SQL时,会使用来判定返回的标量值的实际顺序和类型。如果要避免过多的使用,或者只是为了更加明确的指名返回值,可以使用()。
session.createSQLQuery("select * from note where id = 1") .addScalar("id", LongType.INSTANCE) .addScalar("name", StringType.INSTANCE) .addScalar("createtime", DateType.INSTANCE);
这个查询指定了SQL查询字符串,要返回的字段和类型.它仍然会返回数组,但是此时不再使用,而是明确的将id,name和按照Long, 和Date类型从中取出。同时,也指明了就算query是使用*来查询的,可能获得超过列出的这三个字段,也仅仅会返回这三个字段。
对全部或者部分的标量值不设置类型信息也是可以的:
session.createSQLQuery("select * from note where id = 1") .addScalar("id") .addScalar("name") .addScalar("createtime", DateType.INSTANCE);
没有被指定类型的字段将仍然使用获取其类型。注意,字段不区分大小写,同时不能够指定不存在的字段!
关于从返回的java.sql.Types是如何映射到类型,是由方言()控制的。假若某个指定的类型没有被映射,或者不是你所预期的类型,你可以通过的e调用自行定义。
如果仅指定了一个,那么…
Date createTime = (Date)session.createSQLQuery("select * from note where id = 1") .addScalar("createtime", DateType.INSTANCE) .uniqueResult();
如果我们的SQL语句使用了聚合函数使用Hibernate SQLQuery执行原生SQL,如count、max、min、avg等,且返回结果仅一个字段,那么提供的这种提取标量结果的方式就非常便捷了。
实体查询
上面的查询都是返回标量值的,也就是从中返回的“裸”数据。下面展示如何通过()让原生查询返回实体对象。
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和三个字段的类,以上的两个查询都返回一个List,每个元素都是一个Note实体。

假若实体在映射时有一个many-to-one的关联指向另外一个实体,在查询时必须也返回那个实体,否则会导致发生一个” not found”的数据库错误。这些附加的字段可以使用*标注来自动返回,但我们希望还是明确指明,看下面这个具有指向Dog的many-to-one的例子:
session.createSQLQuery("select id,note,createtime,author from note where id = ?").addEntity(Note.class);
字段即为Note实体和实体的关联字段,只需在查询时得到该字段的值hibernate 原生sql,即可使用该值找到对应的关联实体。如上例中,note.()即可返回当前Note所属的对象。
处理关联和集合类
通过提前抓取将连接获得,而避免初始化proxy带来的额外开销也是可能的。这是通过()方法进行的,这个方法可以让你将关联或集合连接进来。
session.createSQLQuery("select {note.*}, {author.*} from note note, user author where note.author = author.id") .addEntity("note", Note.class) .addJoin("author", "note.author");
上面的例子是多对一的关联查询,反过来做一对多的关联查询也是可以的。如下的例子中,.notes表示该用户发表的所有日记(Note)hibernate 原生sql,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查询语句,其中包含占位附来让注入字段别名,查询并返回的实体。
上面使用的{note.*}和{.*}标记是作为“所有属性”的简写形式出现的,当然你也可以明确地罗列出字段名。但如下的范例代码中我们让来为每个属性注入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");
大多数情况下,上面的别名注入方式可以满足需要hibernate 原生sql,但在使用更加复杂的映射,比如复合属性、通过标识符构造继承树,以及集合类等等情况下,则需要更加复杂的别名注入方式。
下表列出了使用别名注射参数的不同方式:
别名注入(alias names) 描述
语法
示例
简单属性
as {item.name}
复合属性
as {item..}, VALUE as {item..value}
实体辨别器
.class}
DISC as {item.class}
实体的所有属性
.*}
{item.*}
集合键( key)
.key}

ORGID as {coll.key}
集合id
.id}
EMPID as {coll.id}
集合元素
.}
XID as {coll.}
集合元素的属性
..
NAME as {coll..name}
集合元素的所有属性
..*}
{coll..*}
集合的所有属性
.*}
{coll.*}
在hbm文件中描述结果集映射信息,并在查询中使用
对于一些复杂的结果集映射,往往需要像那样在文件中手动配置好,然后在程序中使用。幸运的是也提供了类似的功能,你可以使用自己配置的结果集映射来处理返回的结果集数据:
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();
执行更新操作
使用执行数据库更新操作比较容易使用Hibernate SQLQuery执行原生SQL,除了像查询时那样需要指定SQL语句(如有需要还需设置SQL参数)外,仅需调用()方法,即可提交更新操作。代码如下所示:
session.createSQLQuery("update createtime = ? from note where note.id = ?");query.setDate(0, new Date());query.setLong(1, 1L);query.executeUpdate();
方法的返回结果为改变的数据库记录的行数。
1. 本站所有资源来源于用户上传和网络,如有侵权请联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系站长处理!
6. 本站不售卖代码,资源标价只是站长收集整理的辛苦费!如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。
7. 站长QQ号码 2205675299
资源库 - 资源分享下载网 » 使用Hibernate SQLQuery执行原生SQL
常见问题FAQ
- 关于资源售价和售后服务的说明?
- 代码有没有售后服务和技术支持?
- 有没有搭建服务?
- 链接地址失效了怎么办?
- 关于解压密码

