问题描述:在Hibernate5中,使用原生SQL进行多表查询,并将其结果通过Struts2返回给前台的ajax请求、bootstrap-table请求。
1. 数据库
数据库的表格数据大致如下:
- Invest表:
id | projectname | investorid | investmoney |
---|---|---|---|
1 | SSFW | 1 | 100 |
2 | Universe | 1 | 150 |
3 | Universe | 2 | 200 |
- User表:
userid | username |
---|---|
1 | pcy |
2 | kjd |
表之间的关系是用户投资项目,也就是investorid是Invest表的外键,对应userid。
现需要将投资项目Universe的username(用户名)和investmoney(投资金额)展示出来,这里以左外连接(left join)为例。
2. Hibernate原生SQL多表查询
如果用hql进行多表查询,需要在实体类和映射文件中配置一对多、多对一、多对多的关系,这里选择直接用原生sql操作。
在Dao层实现类中,继承HibernateDaoSupport类(
extends HibernateDaoSupport
),并在applicationContext.xml文件的Dao层配置中注入sessionFactory:<bean id="xxxDao" class="..."> <property name="sessionFactory" ref="sessionFactory"/> </bean>
这样做便于后续步骤中获取Hibernate原生SQL语句的接口和使用模板中的方法,否则在获取session的时候可能会报空指针异常。
原生SQL的生成及其查询结果
import java.util.List; import org.hibernate.query.Query; import org.hibernate.Session; import org.springframework.orm.hibernate5.support.HibernateDaoSupport; /** * 根据项目名称,invest左外连接user查询投资人信息 */ public List<Object[]> getInvestorInfoList(String projectname) { //通过模板获取Hibernate session对象 Session session = this.getSessionFactory().openSession(); //sql语句 String sql = "select u.username, i.investmoney from Invest i left join User u on i.investorid=u.userid where i.projectname=:projectname"; //运行sql并绑定参数 Query query = session.createQuery(sql); query.setParameter("projectname", projectname); List<Object[]> list = query.getResultList(); return list; }
常见错误:
- 引入的包为
import org.hibernate.query.Query
,这里是因为Hibernate5将以前版本的org.hibernate.Query
更改了,题主按照以前的包引入会报错,实际情况如果不报错的话也可以,但是这里确实是一个比较容易出错的点。 - 很多博客中省略了
Session session = this.getSessionFactory().openSession();
,直接用了session.createQuery()
方法,这里很关键。 - 关于sql绑定参数的问题,Hibernate5中不再使用
setParameter(0,xxx)
(对应sql中?
的位置)的形式,所以在sql语句中添加对应格式的参数占位,并根据名称绑定。 - 如果查询结果中有多列,这里指username、investmoney,又不想新建一个实体类,那么返回的对象是
List<Object[]>
比较好,否则最后数据封装的时候不方便改为键值对的形式,也就是ajax、bootstrap-table、json需要的形式。 select from
后面不是数据库中的表名,而是经Hibernate映射后的实体名,否则会报找不到表的错误。
3. Action封装数据
由于获取的是List<Object[]>
(对象数组,每个对象中有两个及以上的数据),需要将其改为[{"key":"value","key":"value"},{"key":"value","key":"value"},{"key":"value","key":"value"}]
的形式。
这里选择使用Map<String,Object>
类型表示每个对象的键值对,最终的数据类型就是List<Map<String,Object>>
,即键值对对象的数组,转换过程如下:
//获取list
List<Object[]> list = investService.getInvestorInfoList(projectname);
//将其转换为键值对数组
List<Map<String,Object>> result = new ArrayList<Map<String, Object>>();
for (Object[] objects : list) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("username", objects[0]);
map.put("investmoney", objects[1]);
result.add(map);
}
这里可以选择返回这个result
数组,在struts2中通过继承json-default
和引入struts2-json-plugin-.jar
包转换为json格式;也可以直接将整个List<Object[]>
对象转换为json数据直接返回。
如果用了确定后台运行成功并返回正确数据,但前台无法获取数据,可以参考这篇博客ajax接收不到struts2返回数据的问题
写在最后
用SSH框架时遇到了如上问题和注意点,所以做个汇总记录贴,如果还遇到其他问题或不完善处,欢迎评论留言讨论。