Hibernate执行原生态SQL语句通用方法
????? 最近在给系统(原系统是Hibernate做的持久层)加一些统计方面的功能,一般用Hihbernate都是用DAO类继承org.springframework.orm.hibernate.support.HibernateDaoSupport类的getHibernateTemplate()方法来获取链接执行HQL语句。可是有时(如做一些统计功能时)一些比较复杂的SQL在转换成HQL比较麻烦时就希望Hibernate能直接SQL(不想在系统外再去加一个JDBC拉链)。
注:对参数cls(VO对象)的要求:cls对象的setter方法名get后的字母全大写(如:setMAXACCEPTDATE)
???? ?参考: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 我的第一篇博客,记录一下学习过程。 /** * @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; }
?
?
?
你把conn=this.getHibernateTemplate().getSessionFactory().openSession().connection(); 这句换成 JDBCUtil.getConnection()后就是最早的JDBC做法了。
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
/**
* 通过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);
}
/**
* 通过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();报错,不知是怎么获取的?
这样只要在原系统中加一个方法就可以完成一个或多个的统计功能(就是不想多改动原系统中一些底层DAO类),其它的一些些写法我基本上也都试过,可是在我的系统中行不通。
谢谢各位的观注和回复!
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被关闭异常,不过重新请求一下就可以取到值了
现在还在找原因,请大家多多指教。
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();
}
});
}
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(); 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框架,这个想法很早就有人想到了的。。。
楼主能想到,那也是不错的。