1.简述
之前在使用Hibernate来处理一些复杂逻辑时,比如:多表连接查询,存放返回的结果集非常麻烦,就在最近发现了一个非常好用的处理方法,那就是将多表连接查询的每一组结果存放入非持久化对象内,然后再将一个个非持久化对象装入链表等结构中,这样一来对结果集的操作就会方便很多。要使用这个方法的前提是hibernate必须是3.2或者以上版本,废话不说了,下面看介绍:
2.非持久化对象的建立
首先要建立好存放查询结果的非持久化对象,这个非持久化对象就是一个普通的实体JavaBean(请注意,这个javabean不需要持久化,就是一个普通的JavaBean,只需要将数据库返回的字段对象上,有 set、get方法即可,要求属性名称和数据类型要与数据库查询结果返回的相应列保持一致,因为返回结果需要对应上javabean的属性)代码如下:
public class SelectCourse { String open_no; //开课编号 String cou_name; //课程名 String tea_name; //教师名 Integer cou_time; //学时 Float cou_score; //课程学分 Integer total_num; //可选总人数 Integer seled_num; //已选人数 public String getOpen_no() { return open_no; } public void setOpen_no(String open_no) { this.open_no = open_no; } public String getCou_name() { return cou_name; } public void setCou_name(String cou_name) { this.cou_name = cou_name; } public String getTea_name() { return tea_name; } public void setTea_name(String tea_name) { this.tea_name = tea_name; } public Integer getCou_time() { return cou_time; } public void setCou_time(Integer cou_time) { this.cou_time = cou_time; } public Float getCou_score() { return cou_score; } public void setCou_score(Float cou_score) { this.cou_score = cou_score; } public Integer getTotal_num() { return total_num; } public void setTotal_num(Integer total_num) { this.total_num = total_num; } public Integer getSeled_num() { return seled_num; } public void setSeled_num(Integer seled_num) { this.seled_num = seled_num; } }
3.数据库语句的书写
数据库语句书写时,返回结果列的名称如果与javaBean中对应属性的名称不同记得给数据库该列取一个与javaBean属性一样的别名,否则就会报错,因为数据库结果集与javaBean无法建立起关联,下面就以数据库中视图的书写为例:
-----查看可选课--- create view view_SC as select Ci.Ci_no as open_no,Cou_name as cou_name,Tea_name as tea_name,Cou_time as cou_time, Cou_score as cou_score,Ci_num as total_num,count(Stu_no) as seled_num from Course C,Teacher T,Course_information Ci full join SC on Ci.Ci_no=SC.Ci_no where Ci.Cou_no=C.Cou_no and Ci.Tea_no=T.Tea_no and Ci.Ci_type=‘通识选修‘ and Ci_status=‘可选‘ group by Ci.Ci_no,Cou_name,Tea_name,Cou_time,Cou_score,Ci_num; go
可以看到视图中查询结果的每一列都给它们取了与javaBean中对应属性名称一样的别名。
4.结果集的存放
使用Hibernate原生态的SQL语句来调用视图,并生成SQLQuery 对象(注意这里要生成SQLQuery对象不能是Query对象,一定不能错,因为Query没有addScalar方法),然后调用addScalar方法来为SQL的每个查询字段设置返回值类型,这个类型需要与javaBean中的对应属性类型一致,最后将查询的结果集映射到由刚刚设置的非持久化对象组成的链表中。
package adc.dao.impl; import java.util.List; import javax.annotation.Resource; import org.hibernate.Query; import org.hibernate.SQLQuery; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.transform.Transformers; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import adc.bean.SelectCourse; @Repository("studao") //对应的dao处理方式 @Transactional //注解事务 public class StuDaoImpl implements IStuDao { @Resource private SessionFactory stusf; public SessionFactory getStusf() { return stusf; } public void setStusf(SessionFactory stusf) { this.stusf = stusf; } //查看所有选修课程 @Override public List<SelectCourse> showSelect() { //调用视图 String sql="select * from view_SC"; Session s = stusf.openSession(); SQLQuery query=s.createSQLQuery(sql); //为每个sql中的查询的字段设置返回的类型 query.addScalar("open_no", new org.hibernate.type.StringType()); query.addScalar("cou_name", new org.hibernate.type.StringType()); query.addScalar("tea_name", new org.hibernate.type.StringType()); query.addScalar("cou_time", new org.hibernate.type.IntegerType()); query.addScalar("cou_score", new org.hibernate.type.FloatType()); query.addScalar("total_num", new org.hibernate.type.IntegerType()); query.addScalar("seled_num", new org.hibernate.type.IntegerType()); //将返回结果集存放入由非持久化对象SelectCourse组成的链表中 List<SelectCourse> list=query.setResultTransformer(Transformers.aliasToBean(SelectCourse.class)).list(); s.close(); return list; } }
5.该方法的几点说明
1.该方法可以存放直接查询语句返回的结果集,也可以存放间接查询语句返回的结果集。所谓的直接查询就是单独的查询语句,间接查询就是视图、存储过程、函数等内部使用了查询语句,然后返回一个结果集。
2.使用该方法来存放存储过程、函数等返回的结果集时可能会报“该语句没有结果集”的错误,在确定有返回结果集的情况下,很可能是因为数据库的驱动会关注到存储过程、函数等执行过程中返回的“影响多少行”这些信息,有这些信息存在,就会抛出以上异常。
解决办法:在sql语句前加“SET NOCOUNT ON ”,表示不返回计数(表示受 Transact-SQL 语句影响的行数)。示例如下所示:
create procedure pro_defeate @no int as begin SET NOCOUNT ON; update Course_apply set Ca_status=‘不通过‘ where Ca_no=@no; select 1 as mystatus; end go
6.参考资料
【1】https://blog.csdn.net/u011687186/article/details/50955307
【2】https://blog.csdn.net/peanuthul/article/details/5776770