`
chenxr
  • 浏览: 36299 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Hibernate执行原生态SQL语句通用方法

阅读更多

Hibernate执行原生态SQL语句通用方法

      最近在给系统(原系统是Hibernate做的持久层)加一些统计方面的功能,一般用Hihbernate都是用DAO类继承org.springframework.orm.hibernate.support.HibernateDaoSupport类的getHibernateTemplate()方法来获取链接执行HQL语句。可是有时(如做一些统计功能时)一些比较复杂的SQL在转换成HQL比较麻烦时就希望Hibernate能直接SQL(不想在系统外再去加一个JDBC拉链)。

注:对参数cls(VO对象)的要求:cls对象的setter方法名get后的字母全大写(如:setMAXACCEPTDATE)

    

                /**
	 * @author crsystem
	 * @param sql SQL语句
	 * @param cls 查询结果集(ResultSet)转换成ArrayList时要用到的VO对象(如:GatherNodeVO.class)
	 * @return ResultSet
	 * 通过Hibernate 执行原生态的SQL语句通用方法
	 * 对参数cls(VO对象)的要求:cls对象的setter方法名get后的字母全大写(如:setMAXACCEPTDATE)
	 */
                @SuppressWarnings("unchecked")
	public List getListBysql(String sql,Class cls){
		List list=new ArrayList();
		Connection conn=null;
		Statement stm=null;
		ResultSet rs=null;
		try {
			conn=this.getHibernateTemplate().getSessionFactory().openSession().connection();
			stm = conn.createStatement();
			rs=stm.executeQuery(sql);
			ResultSetMetaData rsmd = rs.getMetaData(); //取得数据表中的字段数目,类型等返回结果
		    //是以ResultSetMetaData对象保存
		    int columnCount = rsmd.getColumnCount(); //列的总数
		    while(rs.next()){
		    	Object obj=Class.forName(cls.getName()).newInstance();//类的实例化
		    	for (int i = 1; i <= columnCount; i++) {
		    		//取得ActionForm或VO中的set方法
		    		String colName=rsmd.getColumnName(i); //获取字段名 (全大写) 
		    		//System.out.println("AAA "+colName);
                    colName=colName.replace(colName.charAt(0)+"", new String(colName.charAt(0)+"").toUpperCase()); //将字段名字母全大写  
                    String methodName="set"+colName;   //拼出setter方法名
                    //System.out.println("bbb "+methodName);   
                    
                    Object value=rs.getObject(i);//获取字段值   
                    //获得Model类的set方法,获取字段的类型设置为set方法的参数类型
                    Method method=obj.getClass().getMethod(methodName, value.getClass()); 
                    //调用set方法,将获取到的字段值设置到obj对象中
                    method.invoke(obj, value);   
		    	}
		    	list.add(obj);
		    }
		} catch (HibernateException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}finally{
			try {
//				if(null != rs){
//					rs.close();
//				}
				if(null != stm){
					stm.close();
				}
				if(null != conn){
					conn.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return list;	
	}
 

 参考:http://ibc.iteye.com/blog/247126

         http://blog.csdn.net/alexjjf/archive/2007/02/07/1504876.aspx

         http://www.blogjava.net/jrkui188/archive/2007/12/23/169757.html

         http://lavasoft.blog.51cto.com/62575/15433

我的第一篇博客,记录一下学习过程。

 

 

分享到:
评论
16 楼 fengfeng925 2010-05-28  
楼主这是jdbc吧,没看出来跟hibernate没什么关系吧。
15 楼 maozj 2010-05-24  
chenxr 写道
实际应用中发现用
conn=this.getHibernateTemplate().getSessionFactory().openSession().connection(); 
stm = conn.createStatement(); 
rs=stm.executeQuery(sql); 

不是很稳定,有时,偶尔会报
java.sql.SQLException: You can't operate on a closed Statement!!!
	at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:104)
	at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:65)
	at com.mchange.v2.c3p0.impl.NewProxyStatement.executeQuery(NewProxyStatement.java:44)
	at lwoa.bus.imp.VAllQueryMgr.getListBysql(VAllQueryMgr.java:280)

错误指向
rs=stm.executeQuery(sql);

这行代码。
后来改为:
conn=this.getSession().connection();
stm=conn.createStatement();
rs=stm.executeQuery(sql);

也能获取jdbc链接,目前还没测出

conn=this.getHibernateTemplate().getSessionFactory().openSession().connection();  
这个方法可以用,但已经过时了。

另外,这样做可以绕过hibernate框架,提高性能。

但脱离框架的写法,不符合框架模式,用了框架一般是基于框架思想的。

但在提高性能的模块可以绕过hibernate框架,这个想法很早就有人想到了的。。。

楼主能想到,那也是不错的。
14 楼 chenxr 2010-05-24  
实际应用中发现用
conn=this.getHibernateTemplate().getSessionFactory().openSession().connection(); 
stm = conn.createStatement(); 
rs=stm.executeQuery(sql); 

不是很稳定,有时,偶尔会报
java.sql.SQLException: You can't operate on a closed Statement!!!
	at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:104)
	at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:65)
	at com.mchange.v2.c3p0.impl.NewProxyStatement.executeQuery(NewProxyStatement.java:44)
	at lwoa.bus.imp.VAllQueryMgr.getListBysql(VAllQueryMgr.java:280)

错误指向
rs=stm.executeQuery(sql);

这行代码。
后来改为:
conn=this.getSession().connection();
stm=conn.createStatement();
rs=stm.executeQuery(sql);

也能获取jdbc链接,目前还没测出
13 楼 duanwenguo 2010-05-17  
我也发现这种需求,在做报表统计查询的时候需要原生态sql语句操作,这是我采用的方法,可以直接对sql进行操作,其实就是利用 HibernateCallback接口,HibernateCallback实例可在任何有效的Hibernate数据访问中使用


public List executeQuerySql(final String sql, final Object[] values){
    return (List) super.getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Query queryObject = session.createSQLQuery(sql);
if (values != null) {
for (int i = 0; i < values.length; i++)queryObject.setParameter(i, values[i]);
}
return queryObject.list();
}
});
    }
12 楼 long21kk 2010-05-17  
想说。。。这是JDBC,干脆用JDBC好了,没必要这样强逼自己用hibernate
11 楼 chenxr 2010-05-10  
虽然有点标题*了,但是通过Hibernate的数据库链接来实现的,看过lgdlgd(http://lgdlgd.iteye.com/blog/473147)实现方式,也是要写一个VO对用SQL取出来的数据转一道,很好,学习了。只是他用的是Hibernate3.25而我系统中是hibernate2.0用不了
 Query query = this.getSession().createSQLQuery(queryString);   

在实际应用中发现有时从数据库中取出的字段有时为NULL时用我上面的方法不能处理现在把更改后的贴出来:
引用

@SuppressWarnings("unchecked")
public List getListBysql(String sql,Class cls){
List list=new ArrayList();
Connection conn=null;
Statement stm=null;
ResultSet rs=null;
try {
conn=this.getHibernateTemplate().getSessionFactory().openSession().connection();
stm = conn.createStatement();
rs=stm.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData(); // 取得数据表中的字段数目,类型等返回结果
    // 是以ResultSetMetaData对象保存
    int columnCount = rsmd.getColumnCount(); // 列的总数
    while(rs.next()){
    Object obj=Class.forName(cls.getName()).newInstance();// 类的实例化
    for (int i = 1; i <= columnCount; i++) {
    // 取得ActionForm或VO中的set方法
    String colName=rsmd.getColumnName(i); // 获取字段名 (全大写)
    // System.out.println("AAA "+colName);
                    colName=colName.replace(colName.charAt(0)+"", new String(colName.charAt(0)+"").toUpperCase()); // 将字段名字母全大写
                    String methodName="set"+colName;   // 拼出setter方法名
                    // System.out.println("bbb "+methodName);
                   
                    Object value=rs.getObject(i);// 获取字段值
                    if(value==null){//对于从数据库中取出为NULL的字段给默认值
                    Field field=cls.getDeclaredField(colName);
                    String fieldType=field.getType().toString();
                    if("class java.lang.String".equals(fieldType)){
                    value=new String("");
                    }else if("class java.lang.Integer".equals(fieldType)){
                    value=new Integer(0);
                    }else if("class java.lang.Long".equals(fieldType)){
                    value=new Long(0);
                    }else if("int".equals(fieldType)){
                    value=0;
                    }else if("long".equals(fieldType)){
                    value=0;
                    }else if("byte".equals(fieldType) || "short".equals(fieldType)){//下面是不常用的
                    value=0;
                    }else if("float".equals(fieldType) || "double".equals(fieldType)){
                    value=0.0;
                    }else if("char".equals(fieldType)){
                    value=0;
                    }else if("boolean".equals(fieldType)){
                    value=false;
                    }else if("class java.lang.Byte".equals(fieldType)){
                    byte b=0;
                    value=new Byte(b);
                    }else if("class java.lang.Short".equals(fieldType)){
                    value=new Short("0");
                    }else if("class java.lang.Boolean".equals(fieldType)){
                    boolean b=false;
                    value=new Boolean(b);
                    }else if("class java.lang.Character".equals(fieldType)){
                    char c=0;
                    value=new Character(c);
                    }else if("class java.lang.Float".equals(fieldType)){
                    float f=0;
                    value=new Float(f);
                    }else if("class java.lang.Double".equals(fieldType)){
                    double d=0;
                    value=new Double(d);
                    }else{
                    value=0;
                    }
                    }
                    // 获得Model类的set方法,获取字段的类型设置为set方法的参数类型
                    Method method=obj.getClass().getMethod(methodName, value.getClass());
                    // 调用set方法,将获取到的字段值设置到obj对象中
                    method.invoke(obj, value);  
    }
    list.add(obj);
    }
} catch (HibernateException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}finally{
try {
// if(null != rs){
// rs.close();
// }
if(null != stm){
stm.close();
}
if(null != conn){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return list;
}

在我的系统中测试时偶而会出现ResultSet被关闭异常,不过重新请求一下就可以取到值了
现在还在找原因,请大家多多指教。
10 楼 chenxr 2010-03-15  
java_fxj 写道
额...有必要写的 这么复杂吗?

这样只要在原系统中加一个方法就可以完成一个或多个的统计功能(就是不想多改动原系统中一些底层DAO类),其它的一些些写法我基本上也都试过,可是在我的系统中行不通。
谢谢各位的观注和回复!
9 楼 lgdlgd 2010-03-13  
确实有点标题党,想进步的话看看这里http://lgdlgd.iteye.com/admin/blogs/473147,这也许是此问题是最好的解决方案
8 楼 fish4j 2010-03-05  
天哪...
7 楼 chenxr 2010-03-05  
yangdefeng95802 写道
可以用下面的方法实现
/**
* 通过sql语句查询出符合条件的list
*/
public class ApplicationDAO extends HibernateDaoSupport {
public List findListBySqlQuery(final String queryString) {
return (List) getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session)
throws HibernateException, SQLException {
if(queryString==null) throw new DaoParamException("BaseDao-Check.findPageByQuery - param can not be null");
Long beforTime = System.currentTimeMillis();
Connection conn = getConnection();
Statement stmt = conn.createStatement();
logger.info(queryString);
ResultSet resultSet = (ResultSet)stmt.executeQuery(queryString);
List listResult = new ArrayList();
while(resultSet.next()){


ResultSetMetaData rsmd = resultSet.getMetaData();  
int   columnCount   =   rsmd.getColumnCount();
Object[] arrObj = new Object[columnCount];
for(int j=0;j<arrObj.length;j++){
arrObj[j] = resultSet.getObject(j+1);
}
listResult.add(arrObj);
}
LogExecutionTime(System.currentTimeMillis() - beforTime);
return listResult;
}
}, true);
}

Connection conn = getConnection();报错,不知是怎么获取的?
6 楼 java_fxj 2010-03-05  
额...有必要写的 这么复杂吗?
5 楼 xiaoyiz 2010-03-04  
这样做不如直接使用JDBC或者iBATIS。。没任何意义。。。
4 楼 yangdefeng95802 2010-03-04  
可以用下面的方法实现
/**
* 通过sql语句查询出符合条件的list
*/

public List findListBySqlQuery(final String queryString) {
return (List) getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session)
throws HibernateException, SQLException {
if(queryString==null) throw new DaoParamException("BaseDao-Check.findPageByQuery - param can not be null");
Long beforTime = System.currentTimeMillis();
Connection conn = getConnection();
Statement stmt = conn.createStatement();
logger.info(queryString);
ResultSet resultSet = (ResultSet)stmt.executeQuery(queryString);
List listResult = new ArrayList();
while(resultSet.next()){


ResultSetMetaData rsmd = resultSet.getMetaData();  
int   columnCount   =   rsmd.getColumnCount();
Object[] arrObj = new Object[columnCount];
for(int j=0;j<arrObj.length;j++){
arrObj[j] = resultSet.getObject(j+1);
}
listResult.add(arrObj);
}
LogExecutionTime(System.currentTimeMillis() - beforTime);
return listResult;
}
}, true);
}
3 楼 超级潜水艇 2010-03-04  
Hibernate里记得好像直接有执行原生sql的方法?
2 楼 nothinkinperson 2010-03-04  
标题党,付上两种用法:

return hibernateTemplate.getSessionFactory().getCurrentSession().createSQLQuery(sql)
.setFirstResult(start)
.setMaxResults(size)
.setResultTransformer(Transformers.aliasToBean(CommunityView.class))
.list();



return getMyHibernateTemplate().getSessionFactory().getCurrentSession().createSQLQuery(sql).addEntity("orderItem", SysOrderItem.class).list
1 楼 linliangyi2007 2010-03-04  
楼主标题党,这个就是原始JDBC的操作啊,跟Hibernate啥关系啊,除了通过HIbernate API获取一个connection,其他一点关系都没有啊。

你把conn=this.getHibernateTemplate().getSessionFactory().openSession().connection();  这句换成 JDBCUtil.getConnection()后就是最早的JDBC做法了。


相关推荐

    关于hibernate 的createQuery和createSqlQuery 的区别

    createSqlQuery 方法是 Hibernate 提供的一种查询机制,用于执行原生态的 SQL 语句。与 createQuery 方法不同的是,createSqlQuery 方法可以执行查询、修改和添加操作。 使用 createSqlQuery 方法可以执行以下操作...

    MyBatis面试题 37道.pdf

    与 Hibernate 相比,MyBatis 是一个半自动映射的框架,配置 Java 对象与 SQL 语句执行结果的对应关系,多表关联关系配置简单。Hibernate 是一个全表映射的框架,配置 Java 对象与数据库表的对应关系,多表关联关系...

    MyBatis 常见面试题总结.docx

    程序员直接编写原生态 sql,可以严格控制 sql 执行性能,灵活度高。 MyBatis 的优点: 1. 基于 SQL 语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL 写在 XML 里,解除 sql 与程序代码...

    JPA和Hibernate的关系

    3. **查询语言**:JPA引入了一种名为JPQL(Java Persistence Query Language)的查询语言,这是一种面向对象的查询语言,可以用来执行各种查询操作,而不必直接编写SQL语句。这有助于降低应用与数据库之间的耦合度。...

    mybatis面试题整理详细版

    * Mybatis 直接编写原生态 sql,可以严格控制 sql 执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发。 * Hibernate 对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用 ...

    Java程序员面试,MyBatise常见面试27道必问题

    2. MyBatis 直接编写原生态 sql,可以严格控制 sql 执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发。 3. Hibernate 对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用 ...

    MyBatis的27道面试题

    MyBatis的编写原生态SQL特性赋予了开发者高度的灵活性,可以精确控制SQL的执行,适用于需求变化频繁的互联网项目。 MyBatis的优点主要体现在基于SQL语句编程带来的灵活性,消除了与数据库的耦合,便于统一管理SQL...

    hibernate与ibatis比较的11大优势

    4. **原生SQL的支持**:尽管如此,Hibernate并没有完全放弃对原生SQL的支持,开发者仍然可以在必要时直接编写并执行原生SQL语句。而在iBatis中,所有的查询都必须以XML文件的形式定义,这在一定程度上降低了代码的...

    mybatis-超详细文档-文档

    MyBatis 可以让程序员直接编写原生态 SQL,可以手动映射结果到 Java 对象,同时它也提供了动态 SQL 的支持,极大地简化了 JDBC 编程的复杂性。 **2. MyBatis 的核心组件** - **SqlSessionFactoryBuilder**:用于...

    《Mybatis应用技术》复习资料.doc

    - **灵活性**: MyBatis 允许开发者直接编写原生态 SQL,这使得其在面对需求频繁变更的情况下能够快速适应,同时也提供了更高的性能优化空间。 - **数据库无关性**: 由于 MyBatis 需要手动编写 SQL,因此在需要支持...

    Hibernate5用户手册中文版

    - 还涉及如何配置数据库方言(Database Dialect),以便Hibernate能够生成与特定数据库兼容的SQL语句。 6. **事务与并发控制**: - 介绍了物理事务的管理方式和Hibernate的事务API。 - 讨论了不同事务模式(如...

    hibernate 的好处

    - **支持原生 SQL**:虽然 Hibernate 鼓励使用 HQL,但它同样支持使用原生 SQL,这对于需要执行复杂查询的情况非常有用。 - **XML 文件配置**:Hibernate 可以通过 XML 文件来配置映射关系,这使得整个系统的配置...

    1000道Java工程师面试题.pdf

    - **灵活性高**:MyBatis允许开发者编写原生态SQL,从而提供更高的灵活性。 - **易于上手**:对于简单的操作,只需配置少量XML即可实现数据访问。 - **性能优秀**:相比Hibernate等全ORM框架,MyBatis提供了更细粒度...

    spring 整合JDBC 原创代码

    对于批量操作,JdbcTemplate提供了`batchUpdate(String[] sqls)`方法,可以一次执行多条SQL语句,提高效率。 8. **原创代码示例** 在压缩包中的"复件 SpringJDBC"文件可能包含一个简单的Spring整合JDBC的示例。...

    传智播客SpringMvc+Mybatis由浅入深视频教程及课程源码资料

    - **强大的SQL语句控制**:允许开发者编写原生态的SQL语句,便于优化。 - **动态SQL**:支持if、choose、when、otherwise等元素,可以根据条件动态生成不同的SQL语句。 - **缓存机制**:提供了二级缓存机制,可以在...

    mybatis入门

    4. **灵活性**:MyBatis允许开发者编写原生态SQL,并且能够灵活地控制SQL语句,适用于复杂的查询需求。 #### 三、MyBatis基本配置 1. **配置文件结构**: - `mybatis-config.xml`:MyBatis的核心配置文件,包括...

    后端开发框架HibernateORM框架将Java对象映射到数据库表

    - **自动SQL生成**:Hibernate能够自动生成SQL语句,大大减少了手写SQL的需求。 - **透明性**:开发者可以通过简单的注解或XML配置文件来指定对象与数据库表之间的映射关系。 - **缓存机制**:Hibernate提供了内置的...

    mybatis基础及项目实战

    - **灵活性**:允许开发者编写原生态SQL并运用强大的动态SQL语句。 - **简洁性**:通过XML映射文件或注解实现声明式编程。 - **高效性**:通过缓存机制提高性能。 - **易于集成**:可以轻松地与Spring等其他Java...

    JAVA全面知识

    Hibernate的优势在于它可以自动处理SQL语句,减少了手动编写SQL的工作量,并支持对象级的数据操作。 2. **Oracle教程**:Oracle是一种广泛应用的关系型数据库管理系统,游标.doc可能涵盖了如何在Oracle中使用游标...

Global site tag (gtag.js) - Google Analytics