Hibernate使用SQL语句多表查询,并返回类json键值对

问题描述:在Hibernate5中,使用原生SQL进行多表查询,并将其结果通过Struts2返回给前台的ajax请求、bootstrap-table请求。

1. 数据库

数据库的表格数据大致如下:

  1. Invest表:
idprojectnameinvestoridinvestmoney
1SSFW1100
2Universe1150
3Universe2200
  1. User表:
useridusername
1pcy
2kjd

表之间的关系是用户投资项目,也就是investorid是Invest表的外键,对应userid。
现需要将投资项目Universe的username(用户名)和investmoney(投资金额)展示出来,这里以左外连接(left join)为例。

2. Hibernate原生SQL多表查询

如果用hql进行多表查询,需要在实体类和映射文件中配置一对多、多对一、多对多的关系,这里选择直接用原生sql操作。

  1. 在Dao层实现类中,继承HibernateDaoSupport类(extends HibernateDaoSupport),并在applicationContext.xml文件的Dao层配置中注入sessionFactory:

    <bean id="xxxDao" class="...">
    	<property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    

    这样做便于后续步骤中获取Hibernate原生SQL语句的接口和使用模板中的方法,否则在获取session的时候可能会报空指针异常。

  2. 原生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框架时遇到了如上问题和注意点,所以做个汇总记录贴,如果还遇到其他问题或不完善处,欢迎评论留言讨论。


版权声明:本文为qq_37896642原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。