hibernate将本地SQL查询结果封装成对象
hibernate将本地SQL查询结果封装成对象
不知道大家有没有碰过这种情况,迫于很多情况只能用native SQL来查询(如:复杂统计等),然而使用native查询后,结果会被放到object里,要想拿到对应的数据只能由object来强制转换,真的好烦人。因为工作原因,笔者(sourcefour)正在做大量的统计而每次都要进行强制转换,这其实是很麻烦的。我在想如果native SQL查询结果也能够封装对象就好了,于是狠狠的查看了hibernate文档,终于发现了一件令人高兴的事情——native SQL查询的结果也是可以封装成对象滴(具体请看hibernate文档【第16章】)。这种情况不得不高兴啊,于是动手做实验,结果还是令人兴奋的----成功了(^_^)于是将实验结果整理以备以后用。
1. 适用对象
可以将以下几种查询结果用Bean封装起来。通俗点说就是查询出来之后就直接将内容放到了Bean实体里。
总的来说,使用本地SQL查询出来的结果也可以直接放到Bean里,如以下情况(只能想到这么多):
直接使用本地(native)SQL查询(废话,说的不就是使用native sql嘛^_^)
2. 具体实现步骤
2.1. 实体Bean
实体Bean的写法和对象Bean的写法是一样的。区别在于该实体Bean是不需要做Hibernate映射的。
我例子中的Bean如下:
- package com.sourcefour.bean;
- /**
- * 这里说明一下,该Bean中的field没必要一定是数据表中的field。
- * 而应该是DAO中要查询字段的别名,具体请看例子NativeSqlDao,
- * 我想你会明白的
- *
- * @author sourcefour
- */
- public class NativeSqlBean {
- private double maxMos;
- private double minMos;
- private double avgMos;
- private int userCount;
- private String name;
- public double getMaxMos() {
- return maxMos;
- }
- public void setMaxMos(double maxMos) {
- this.maxMos = maxMos;
- }
- public double getMinMos() {
- return minMos;
- }
- public void setMinMos(double minMos) {
- this.minMos = minMos;
- }
- public double getAvgMos() {
- return avgMos;
- }
- public void setAvgMos(double avgMos) {
- this.avgMos = avgMos;
- }
- public int getUserCount() {
- return userCount;
- }
- public void setUserCount(int userCount) {
- this.userCount = userCount;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
2.2. Dao操作
直接上代码:
- package com.sourcefour.dao.base;
- import java.sql.SQLException;
- import java.util.List;
- import javax.annotation.Resource;
- import org.hibernate.HibernateException;
- import org.hibernate.Query;
- import org.hibernate.SQLQuery;
- import org.hibernate.Session;
- import org.hibernate.SessionFactory;
- import org.hibernate.transform.Transformers;
- import org.springframework.orm.hibernate3.HibernateCallback;
- import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
- import org.springframework.transaction.annotation.Propagation;
- import org.springframework.transaction.annotation.Transactional;
- /**
- * @author sourcefour
- */
- @SuppressWarnings("unchecked")
- @Transactional
- public abstract class BaseDaoSupport<T> extends HibernateDaoSupport {
- @Resource(name = "sessionFactory")
- public void setSuperSessionFactory(SessionFactory sessionFactory) {
- super.setSessionFactory(sessionFactory);
- }
- /**
- * 使用sql语句进行分页查询
- *
- * @param sql
- * sql语句
- * @param values
- * 参数
- * @param offSet
- * 第一条记录序号 >-1
- * @param pageSize
- * 每页要显示的记录数 >0
- * @param beanClass
- * 将查询结果转换为<tt>T</tt>对象
- * @param fieldList
- * 查询Bean的成员变量名称
- */
- @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
- public List<T> list(final String sql, final Object[] values, final int offSet, final int pageSize,
- final Class<T> beanClass, final List<String> fieldList) {
- List<T> list = getHibernateTemplate().executeFind(new HibernateCallback() {
- public Object doInHibernate(Session session) throws HibernateException, SQLException {
- SQLQuery sqlQuery = session.createSQLQuery(sql);
- // 添加要查询字段的标量
- AddScalar.addSclar(sqlQuery, beanClass, fieldList);
- Query query = sqlQuery;
- // 转换查询结果为T
- if (beanClass != null) {
- query.setResultTransformer(Transformers.aliasToBean(beanClass));
- }
- if ((values != null) && values.length > 0) {
- int i = 0;
- for (Object obj : values) {
- query.setParameter(i++, obj);
- }
- }
- if (offSet > -1) {
- query.setFirstResult(offSet);
- }
- if (pageSize > 0) {
- query.setMaxResults(pageSize);
- }
- return query.list();
- }
- });
- return list;
- }
- }
亮点在代码中注释的两句。其中AddScalar.addSclar是自己写的,具体请看代码:
- package com.sourcefour.dao.base;
- import java.lang.reflect.Field;
- import java.util.Date;
- import java.util.List;
- import org.hibernate.Hibernate;
- import org.hibernate.SQLQuery;
- /**
- * @author sourcefour
- */
- public class AddScalar {
- /**
- * 将field type 和 Hibernate的类型进行了对应。这里其实不是多余的,如果不进行一定的对应可能会有问题。
- * 问题有两个:
- * 1. 在oracle中我们可能把一些字段设为NUMBER(%),而在Bean中的字段定的是long。那么查询时可能会报:
- * java.math.BeigDecimal不能转换成long等错误
- * 2. 如果不这样写的话,可能Bean中的field就得是大写的,如:name就得写成NAME,userCount就得写成USERCOUNT
- * 这样是不是很扯(V_V)
- *
- * @param <T>
- * @param sqlQuery
- * SQLQuery
- * @param clazz
- * T.class
- * @param fieldList
- * 要查询的成员变量名称
- */
- public static <T> void addSclar(SQLQuery sqlQuery, Class<T> clazz, List<String> fieldList) {
- if (clazz == null) {
- throw new NullPointerException("[clazz] could not be null!");
- }
- if ((fieldList != null) && (fieldList.size() > 0)) {
- Field[] fields = clazz.getDeclaredFields();
- for (String fieldName : fieldList) {
- for (Field field : fields) {
- if (fieldName.equals(field.getName())) {
- if ((field.getType() == long.class) || (field.getType() == Long.class)) {
- sqlQuery.addScalar(field.getName(), Hibernate.LONG);
- } else if ((field.getType() == int.class) || (field.getType() == Integer.class)) {
- sqlQuery.addScalar(field.getName(), Hibernate.INTEGER);
- } else if ((field.getType() == char.class) || (field.getType() == Character.class)) {
- sqlQuery.addScalar(field.getName(), Hibernate.CHARACTER);
- } else if ((field.getType() == short.class) || (field.getType() == Short.class)) {
- sqlQuery.addScalar(field.getName(), Hibernate.SHORT);
- } else if ((field.getType() == double.class) || (field.getType() == Double.class)) {
- sqlQuery.addScalar(field.getName(), Hibernate.DOUBLE);
- } else if ((field.getType() == float.class) || (field.getType() == Float.class)) {
- sqlQuery.addScalar(field.getName(), Hibernate.FLOAT);
- } else if ((field.getType() == boolean.class) || (field.getType() == Boolean.class)) {
- sqlQuery.addScalar(field.getName(), Hibernate.BOOLEAN);
- } else if (field.getType() == String.class) {
- sqlQuery.addScalar(field.getName(), Hibernate.STRING);
- } else if (field.getType() == Date.class) {
- sqlQuery.addScalar(field.getName(), Hibernate.TIMESTAMP);
- }
- }
- }
- }
- }
- }
- }
所有的准备工作都做好了,那么就看我们的具体的DAO操作及单元测试。
具体DAO:
- package com.sourcefour.dao;
- import java.util.ArrayList;
- import java.util.List;
- import org.springframework.stereotype.Repository;
- import com.sourcefour.bean.NativeSqlBean;
- import com.sourcefour.dao.base.BaseDaoSupport;
- /**
- * @author sourcefour
- */
- @Repository
- public class NativeSqlDao extends BaseDaoSupport<NativeSqlBean> {
- public List<NativeSqlBean> listAll(int offSet, int pageSize) {
- String sql = "SELECT MAX(t.mos) maxMos, MIN(t.mos) minMos, AVG(t.mos) avgMos, COUNT(t.id) userCount FROM t_native_sql t";
- List<String> fieldList = new ArrayList<String>();
- fieldList.add("maxMos");
- fieldList.add("minMos");
- fieldList.add("avgMos");
- fieldList.add("userCount");
- return super.list(sql, new Object[] {}, offSet, pageSize, NativeSqlBean.class, fieldList);
- }
- }
说明:sql语句中的别名就是我们Bean中的字段
Junit测试代码:
- package com.sourcefour.test.dao;
- import java.util.List;
- import org.junit.Assert;
- import org.junit.BeforeClass;
- import org.junit.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import com.sourcefour.bean.NativeSqlBean;
- import com.sourcefour.dao.NativeSqlDao;
- /**
- * @author sourcefour
- */
- public class NativeSqlDaoTest {
- private static NativeSqlDao nativeSqlDao;
- private static ApplicationContext applicationContext;
- @BeforeClass
- public static void setUp() {
- applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
- nativeSqlDao = (NativeSqlDao) applicationContext.getBean("nativeSqlDao");
- }
- @Test
- public void testListIntInt() {
- List<NativeSqlBean> list = nativeSqlDao.listAll(-1, -1);
- Assert.assertNotNull(list);
- for (NativeSqlBean nativeSqlBean : list) {
- System.out.println("maxMos: " + nativeSqlBean.getMaxMos());
- }
- }
- }
运行结果:

到了这里应该说一切OK鸟。
完整的文档,SQL,工程下载地址:CSDN下载
说明:本说明是关于资源附件的,在资源中附件名称叫做 ‘hibernate将本地SQL查询结果封装成对象(最终)’,其实只有一版,这里只所以叫最终版是因为该附件我上传了好几天传不上去,到最后报告说‘资源已经存在’,但我确实没有看到附件。所以没办法只能改个名字了…………
hibernate将本地SQL查询结果封装成对象的更多相关文章
- Hibernate之QBC查询与本地SQL查询
1. QBC查询: QBC 查询就是通过使用Hibernate提供的QueryByCriteria API 来查询对象,这种API封装了SQL语句的动态拼装,对查询提供了更加面向对象的功能接口 ...
- Hibernate的四种查询方式(主键查询,HQL查询,Criteria查询,本地sql查询)和修改和添加
Hibernate的添加,修改,查询(三种查询方式)的方法: 案例演示: 1:第一步,导包,老生常谈了都是,省略: 2:第二步,创建数据库和数据表,表结构如下所示: 3:第三步创建实体类User.ja ...
- 13.hibernate的native sql查询(转自xiaoluo501395377)
hibernate的native sql查询 在我们的hibernate中,除了我们常用的HQL查询以外,还非常好的支持了原生的SQL查询,那么我们既然使用了hibernate,为什么不都采用hi ...
- hibernate的native sql查询
在我们的hibernate中,除了我们常用的HQL查询以外,还非常好的支持了原生的SQL查询,那么我们既然使用了hibernate,为什么不都采用hibernate推荐的HQL查询语句呢?这是因为HQ ...
- 本地SQL查询
-------------------siwuxie095 本地 SQL 查询 1.简单介绍 采用 HQL 或 QBC 查询时,Hibernate 生成标准的 SQL 语句, 适用于所有的数据库平台, ...
- hibernate 5原生sql查询测试学习代码
基本查询 import java.util.List; import org.hibernate.SQLQuery; import org.hibernate.Session; import org. ...
- hibernate使用原生SQL查询返回结果集的处理
今天没事的时候,看到公司框架里有一个用原生SQL写的函数,说实在以前自己也干过这事,但好久都没有用,都忘得差不多了,现在基本都是用的hql语句来查询结果.hibernate中使用createSQLQu ...
- Hibernate SQLQuery 原生SQL 查询及返回结果集处理-1
第一篇:官方文档的处理方法,摘自官方 在迁移原先用JDBC/SQL实现的系统,难免需要采用hibernat native sql支持. 1.使用SQLQuery hibernate对原生SQL查询执行 ...
- Java JDBC利用反射技术将查询结果封装为对象
1.JDBC将返回结果集封装成对象demo class JdbcDemo { /** * 获取数据库列名 * @param rs * @return */ private static String[ ...
随机推荐
- [Android UI] Shape详解 (GradientDrawable)
转载自:http://blog.csdn.net/feng88724/article/details/6398193 在Android开发过程中,经常需要改变控件的默认样式, 那么通常会使用多个图片来 ...
- 打开genesis时一直在等待,后出现Timeout in communication read解决方法
运行输入:netsh winsock reset 然后重启电脑
- 用php输入表格内容
<body> <table width="100%" border="1" cellpadding="0" cellspa ...
- jquery require.js AMD
一.为什么要用require.js? 最早的时候,所有Javascript代码都写在一个文件里面,只要加载这一个文件就够了.后来,代码越来越多,一个文件不够了,必须分成多个文件,依次加载.下面的网页代 ...
- Entity Framework 使用
1.EF中Include方法的使用使用Include方法,告诉EF连接查询哪个外键属性,生成Inner join连接 //必须引用using System.Data.Entity;才能用Include ...
- [编辑器] Tab转换成空格
Notepad++: 设置 -> 首选项 -> 制表符设置 怎样设置EditPlus中Tab用空格替换http://jingyan.baidu.com/article/63f236280b ...
- mysql的日期存储字段比较int,datetime,timestamp区别
1.首先是我们分析datetime长度是8个字节,INT的长度是4个字节,存储空间上比datatime少. 2.int存储索引的空间也比datetime少,排序效率高,查询速度比较快. 3.方便计算, ...
- Xamarin.Android开发实践(十)
Xamarin.Android之SQLiteOpenHelper 一.前言 在手机中进行网络连接不仅是耗时也是耗电的,而耗电却是致命的.所以我们就需要数 据库帮助我们存储离线数据,以便在用户未使用网络 ...
- wp8
请问如何在应用内跳转到 显示 来自XX的更多应用? Windows.System.Launcher.LaunchUriAsync(new Uri("zune:search?pu ...
- hdu 1728 bfs **
简单bfs,记录好状态即可 #include<cstdio> #include<iostream> #include<algorithm> #include< ...