13.hibernate的native sql查询(转自xiaoluo501395377)
hibernate的native sql查询
在我们的hibernate中,除了我们常用的HQL查询以外,还非常好的支持了原生的SQL查询,那么我们既然使用了hibernate,为什么不都采用hibernate推荐的HQL查询语句呢?这是因为HQL查询语句虽然方便我们查询,但是基于HQL的查询会将查询出来的对象保存到hibernate的缓存当中,如果在我们的一个大型项目中(数据量超过了百万级),这个时候如果使用hibernate的HQL查询的话,会一次将我们查询的对象查询出来后放到缓存中,这个时候会影响我们的效率,所以当在大型项目中使用hibernate时我们的最佳实践就是--使用原生的SQL查询语句,而不使用HQL语句,因为通过SQL查询的话,是不会经过hibernate的缓存的。接下来我们就来看看hibernate的原生SQL查询
1.标量查询
在hibernate中,我们如果使用原生SQL查询的话,是通过SQLQuery接口进行的,我们首先来看看我们最基本的查询:
session.createSQLQuery("select * from t_student s").list()
session.createSQLQuery("select ID,NAME,SEX from t_student s").list()
这就创建了最简单的两条SQL查询语句,此时返回的数据库表的字段值是保存在一个Object[]数组中的,数组中的每个元素就是查询出来的t_student表中的每个字段值,Hibernate会通过ResultSetMetadata来判断每个字段值的存放位置以及类型,接下来我们看下标量查询:
List<Object[]> stus = (List<Object[]>)session.createSQLQuery("select * from t_student s")
.addScalar("ID")
.addScalar("NAME")
.setFirstResult(0).setMaxResults(20)
.list();
这个查询语句指定了查询的字符串以及返回的字段和类型
这条查询语句仍然会返回一个Object[]类型的数组,但是此时就不会通过ResultSetMetadata,而是我们明确指定的ID,NAME,SEX,此时虽然查询语句中有 * 将所有的字段查询出来,但是这个时候仅仅只会返回我们指定的三个字段值,其类型还是由ResultSetMetada来指定的。
2.实体查询
①返回一个实体对象
上述的标量查询返回的裸数据,保存到了Object[]数组当中,我们如果要一个实体对象,将其保存到实体对象时就可以使用 addEntity()方法来实现:

@Test
public void testSql1()
{
Session session = null;
try
{
session = HibernateUtil.openSession();
/*
* 原生的SQL语句查询,会将t_student表的所有字段查出来,存放的一个Object[]数组当中
* 如果希望转换成实体对象,只需要调用 addEntity(Student.class)即可,这时,会首先匹配
* Student对象里面的属性是否全部查询出来,如果没有,则报错(如果这个类是实体类)
* 注意:如果要调用addEntity方法,这个类必须是实体类,即加了@Entity注解或者在XML中配置了实体类
* 映射关系
*/
List<Student> stus = (List<Student>)session.createSQLQuery("select * from t_student s")
.addEntity(Student.class)
.setFirstResult(0).setMaxResults(20)
.list();
for(Student stu : stus)
{
System.out.println(stu.getName());
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
HibernateUtil.close(session);
}
}

这时我们就指定了将查询出来的对象存进Student这个实体类中,注意:如果使用了实体对象,那么在查询时要将实体对象中有的属性全部在SQL语句中查询出来,否则就会报错。
②返回多个实体对象
有的时候我们可能不只查询出一个实体对象,在使用连接查询时候,我们可能需要将几个表的数据都查询出来,并存放到对应的实体对象中去,这个时候我们应该怎么写呢?先看下如下一种写法:

List<Object[]> stus = (List<Object[]>)session.createSQLQuery("select stu.*, cla.*, spe.*"
+ " from t_student stu left join t_classroom cla on stu.rid=cla.id"
+ " left join t_special spe on spe.id=cla.sid where stu.name like ?")
.addEntity("stu", Student.class)
.addEntity("cla", Classroom.class)
.addEntity("spe", Special.class)
.setFirstResult(0).setMaxResults(20)
.setParameter(0, "%张%")
.list();

我们这里通过addEntity的一个重载方法给每个别名指定了一个关联的实体类,这个时候就会出现字段名冲突的问题,我们的本意是查询出三个实体对象,分别取得其name属性,但是name属性在这三张表中的字段都是name,这个时候查询出来的三个实体对象中的属性值都是一样的。我们如果要解决这个方法,只需要用一个 {} 花括号占位符将每个表的所有属性值括起来即可。如下:

@Test
public void testSql3()
{
Session session = null;
try
{
session = HibernateUtil.openSession();
/**
* 当使用连接查询查询多个对象时,可以通过addEntity("alias", XXX.class)方法来根据
* 数据库表的别名来引入多个实体类,这时如果需要将查询出来的所有的对象分别存入实体类中,
* 只需要在查询出来的对象上添加 {} 号即可,此时就会自动帮我们分类
*/
List<Object[]> stus = (List<Object[]>)session.createSQLQuery("select {stu.*}, {cla.*}, {spe.*}"
+ " from t_student stu left join t_classroom cla on stu.rid=cla.id"
+ " left join t_special spe on spe.id=cla.sid where stu.name like ?")
.addEntity("stu", Student.class)
.addEntity("cla", Classroom.class)
.addEntity("spe", Special.class)
.setFirstResult(0).setMaxResults(20)
.setParameter(0, "%张%")
.list();
for(Object[] obj : stus)
{
Student stu = (Student)obj[0];
Classroom cla = (Classroom)obj[1];
Special spe = (Special)obj[2];
System.out.println(stu.getName() + ", " + cla.getName() + ", " + spe.getName());
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
HibernateUtil.close(session);
}
}

③返回不受hibernate管理的实体对象
我们有时候的需求是这样的,将每个表其中的一些字段查询出来,然后存放到一个javabean对象中,但是我们的这个bean对象又不需要存放到数据库,不需要设置成实体对象,这个时候我们往往会创建一个 DTO 的数据传输对象来存放我们要储存的属性,例如定义了一个 StudentDTO 对象:

public class StudentDTO
{
private int sid; // 学生id
private String sname; // 学生姓名
private String sex; // 学生性别
private String cname; // 班级名
private String spename; // 专业名 public StudentDTO(){} public StudentDTO(int sid, String sname, String sex, String cname,
String spename)
{
super();
this.sid = sid;
this.sname = sname;
this.sex = sex;
this.cname = cname;
this.spename = spename;
}
................
}

这个时候我们来看看我们的查询语句:

@Test
public void testSql4()
{
Session session = null;
try
{
/**
* 对于非Entity实体对象的类,我们如果要保持数据,可以通过定义一个DTO对象
* 然后调用setResultTransformer(Transformers.aliasToBean(StudentDTO.class))方法
* 来返回一个不受管的Bean对象
*/
session = HibernateUtil.openSession();
List<StudentDTO> stus = (List<StudentDTO>)session.createSQLQuery("select "
+ "stu.id as sid, stu.name as sname, stu.sex as sex, cla.name as cname, spe.name as spename"
+ " from t_student stu left join t_classroom cla on stu.rid=cla.id"
+ " left join t_special spe on spe.id=cla.sid where stu.name like ?")
.setResultTransformer(Transformers.aliasToBean(StudentDTO.class))
.setFirstResult(0).setMaxResults(20)
.setParameter(0, "%张%")
.list();
for(StudentDTO std : stus)
{
System.out.println(std.getSname() + ", " + std.getCname() + ", " + std.getSpename());
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
HibernateUtil.close(session);
}
}

我们要将查询出来的这些不同的表的字段存放到一个不是实体对象当中,就可以调用 .setResultTransformer(Transformers.aliasToBean(StudentDTO.class)) 方法来创建一个非受管的 bean 对象,这个时候就hibernate就会将属性值存放到这个 bean 对象当中,注意:查询出来的表的字段值存放到bean对象中,是通过调用 bean对象的 setter方法,如果该属性在bean对象中没有setter方法,则会报错。
本篇随笔主要分析了一下如何来通过原生的SQL语句查询我们需要的信息,我们一定要记住,当数据量非常大的时候,强烈建议使用原生的SQL去查询数据,而不要使用HQL来查询,这样其实使用hibernate来说效率其实也不差,但是我们的增、删、改的操作则完全可以交给hibernate来完成。
13.hibernate的native sql查询(转自xiaoluo501395377)的更多相关文章
- hibernate的native sql查询
在我们的hibernate中,除了我们常用的HQL查询以外,还非常好的支持了原生的SQL查询,那么我们既然使用了hibernate,为什么不都采用hibernate推荐的HQL查询语句呢?这是因为HQ ...
- hibernate将本地SQL查询结果封装成对象
hibernate将本地SQL查询结果封装成对象 不知道大家有没有碰过这种情况,迫于很多情况只能用native SQL来查询(如:复杂统计等),然而使用native查询后,结果会被放到object里, ...
- hibernate使用原生SQL查询返回结果集的处理
今天没事的时候,看到公司框架里有一个用原生SQL写的函数,说实在以前自己也干过这事,但好久都没有用,都忘得差不多了,现在基本都是用的hql语句来查询结果.hibernate中使用createSQLQu ...
- Hibernate SQLQuery 原生SQL 查询及返回结果集处理-1
第一篇:官方文档的处理方法,摘自官方 在迁移原先用JDBC/SQL实现的系统,难免需要采用hibernat native sql支持. 1.使用SQLQuery hibernate对原生SQL查询执行 ...
- hibernate 5原生sql查询测试学习代码
基本查询 import java.util.List; import org.hibernate.SQLQuery; import org.hibernate.Session; import org. ...
- 使用Hibernate+MySql+native SQL的BUG,以及解决办法
本来是mssql+hibernate+native SQL 应用的很和谐 但是到了把mssql换成mysql,就出了错(同样的数据结构和数据). 查询方法是: String sql = " ...
- hibernate在使用sql查询query自动转化成model类型数据,query.addEntity
hibernate使用自动的hql查询或者其封装的查询方法都能字段转化成对象 而如果在hibernate中使用sql时大多返回为Object[]对象 那么如何将object[]转换成model呢,答案 ...
- Hibernate 的原生 SQL 查询
Hibernate除了支持HQL查询外,还支持原生SQL查询. 对原生SQL查询执行的控制是通过SQLQuery接口进行的,通过执行Session.createSQLQuery()获取 ...
- hibernate使用原生SQL查询
以下是Demo测试Hibernate 原生SQL查询: import java.util.Iterator; import java.util.List; import java.util.Map; ...
随机推荐
- js遍历数组对象和非数组对象
//---------for用来遍历数组对象 var i,myArr = ["a","b","c"]; ; i < myArr.len ...
- Attempt to write to field 'android.support.v4.app.FragmentManagerImpl android.support.v4.app.Fragment.mFragmentManager' on a null object reference
E/AndroidRuntime﹕ FATAL EXCEPTION: mainProcess: org.example.magnusluca.drawertestapp, PID: 3624java. ...
- CSS之box-sizing的用处简单介绍
前几天才发现有 box-sizing 这么个样式属性,研究了一番感觉很有意思, 通过指定容器的盒子模型类型,达到不同的展示效果 例如:当一个容器宽度定义为 width:100%; 之后,如果再增加 ...
- Oracle 中的Top写法
由于Oracle不支持select top 语句,所以在Oracle中经常是用order by 跟rownum的组合来实现select top n的查询.简单地说,实现方法如下所示:select 列名 ...
- postman+jenkins+newman做接口测试的持续集成
为何要做接口自动化测试的持续集成? 1. 接口相对稳定,改动少,比起GUI自动化测试来说性价比更加高些,不容易出现GUI自动化那种掉到维护脚本的坑里. 2. 接口测试比较简单,一个规范的接口,测试只需 ...
- ubuntu 开机进入不了图形界面
在开机的时候有注意到空间不足.第二天重启的时候进入不了系统. 但是 ctrl + alt _F6 可以进入shell . 于是估计是空间不足导致进入不了系统. 找到哪里文件夹空间异常的大就可以解决问 ...
- 从安装.net Core 到helloWord(Mac上)
最近听说微软 正式发不了.netCore 1.0 于是就安装了 并安装了vs Code 用于编写一些.net程序 一. .netCore的安装: 首先需要通过brew安装openssl(相信homeB ...
- LWP::UserAgent介绍1
require LWP::UserAgent; my $ua = LWP::UserAgent->new; ); $ua->env_proxy; my $response = $ua-&g ...
- .net通过WCF调用java发布的服务,获取数据
功能描述 java作为后台,连接数据库获取数据,然后发布SOAP services,让.net平台通过WCF进行引用. 实现步骤 1.在项目特定文件夹下,右键->添加服务引用,输入服务的url地 ...
- JAVA中数组总结(课堂总结)
数组的特点: Arrays(数组)一种简单的数据结构元素具有相同的数据类型一旦创建之后,尺寸保持不变元素在内存中连续分布例子一:按引用与按值传递的示例源代码: // PassArray.java // ...