例如:
从第2万条开始取出100条记录
代码:
Query q = session.createQuery("from Cat as c");
q.setFirstResult(20000);
q.setMaxResults(100);
List l = q.list();
那么Hibernate底层如何实现分页的呢?实际上Hibernate的查询定义在
net.sf.hibernate.loader.Loader这个类里面,仔细阅读该类代码,就可以把问题彻底
搞清楚。
Hibernate2.0.3的Loader源代码第480行以下:
代码:
if (useLimit) sql = dialect.getLimitString(sql);
PreparedStatement st = session.getBatcher().prepareQueryStatement(sql,
scrollable);
如果相应的数据库定义了限定查询记录的sql语句,那么直接使用特定数据库的sql语
句。
然后来看net.sf.hibernate.dialect.MySQLDialect:
代码:
public boolean supportsLimit() {
return true;
}
public String getLimitString(String sql) {
StringBuffer pagingSelect = new StringBuffer(100);
pagingSelect.append(sql);
pagingSelect.append(" limit ?, ?");
return pagingSelect.toString();
}
这是MySQL的专用分页语句,再来看net.sf.hibernate.dialect.Oracle9Dialect:
代码:
public boolean supportsLimit() {
return true;
}
public String getLimitString(String sql) {
StringBuffer pagingSelect = new StringBuffer(100);
pagingSelect.append("select * from ( select row_.*, rownum rownum_
from ( ");
pagingSelect.append(sql);
pagingSelect.append(" ) row_ where rownum <= ?) where rownum_ > ?");
return pagingSelect.toString();
}
Oracle采用嵌套3层的查询语句结合rownum来实现分页,这在Oracle上是最快的方式,
如果只是一层或者两层的查询语句的rownum不能支持order by。
除此之外,Interbase,PostgreSQL,HSQL也支持分页的sql语句,在相应的Dialect里
面,大家自行参考。
如果数据库不支持分页的SQL语句,那么根据在配置文件里面
#hibernate.jdbc.use_scrollable_resultset true
默认是true,如果你不指定为false,那么Hibernate会使用JDBC2.0的scrollable
result来实现分页,看Loader第430行以下:
代码:
if ( session.getFactory().useScrollableResultSets() ) {
// we can go straight to the first required row
rs.absolute(firstRow);
}
else {
// we need to step through the rows one row at a time (slow)
for ( int m=0; m<firstRow; m++ ) rs.next();
}
如果支持scrollable result,使用ResultSet的absolute方法直接移到查询起点,如果
不支持的话,使用循环语句,rs.next一点点的移过去。
可见使用Hibernate,在进行查询分页的操作上,是具有非常大的灵活性,Hibernate会
首先尝试用特定数据库的分页sql,如果没用,再尝试Scrollable,如果不行,最后采
用rset.next()移动的办法。
在查询分页代码中使用Hibernate的一大好处是,既兼顾了查询分页的性能,同时又保
证了代码在不同的数据库之间的可移植性。
==============================================
使用Spring JDBC包装基本的CRUD操作
想起来Spring的JDBC还不错,就拿起来研究了一下,顺便也写了个小例子,希望对初学者有点用处
主要注意以下几点:
1. 对于一些特定的小项目中,很多的工作量都在增删改上,而这些代码当然是惊人地相似,所以对5个简单的
方法抽象了一下,以达到共用的目的
2. 主要文件:applicationContext.xml, BaseDAO.java, BaseDAOImp.java, DAORowMapper.java
3. 在BaseDAOImp.java里有一个Main方法可以做测试
4. DB中只要一个表,表名:users, 三个列:id(int,主键),name(varchar), email(varchar)
这只是一个初稿,后面再做修改再与大家分享
继续阅读 "使用Spring JDBC包装基本的CRUD操作" ?
Posted by kevinwu 03:40 PM | 全文 | 评论 (0) | SPRING(24)
April 12, 2007
Spring+Hibernate 复杂查询分页
/**分页包装类
很简单 :)
*/
package com.xing.cms.model.util;
public class Pager {
private int totalPages = 0;
private int totalObjects = 0;
private int pageNumber = 1;
private int pageSize = 3;
private boolean pageAble = true;
private int firstResult;
public void calc(){
totalPages = totalObjects % pageSize == 0 ? totalObjects
/ pageSize : totalObjects / pageSize + 1;
firstResult = (pageNumber - 1) * pageSize;
}
public boolean isPageAble() {
return pageAble;
}
public void setPageAble(boolean pageAble) {
this.pageAble = pageAble;
}
public int getTotalObjects() {
return totalObjects;
}
public void setTotalObjects(int param) {
this.totalObjects = param;
}
public int getTotalPages() {
return totalPages;
}
public void setTotalPages(int param) {
this.totalPages = param;
}
public int getPageNumber() {
return pageNumber;
}
public void setPageNumber(int pageNumber) {
this.pageNumber = pageNumber;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public String toString(){
return("/ntotalPages:" + totalPages +
"/ntotalObjects:" + totalObjects +
"/npageNumber:" + pageNumber +
"/npageSize:" + pageSize +
"/npageAble:" + pageAble +
"/nfirstResult:" + firstResult);
}
public int getFirstResult() {
return firstResult;
}
public void setFirstResult(int firstResult) {
this.firstResult = firstResult;
}
}
/*UserDao 接口*/
package com.xing.cms.model.dao;
import java.util.List;
import com.xing.cms.model.businessobject.User;
import com.xing.cms.model.util.Pager;
public interface UserDao {
public abstract boolean save(User model);
public abstract boolean update(User model);
public abstract User get(int id);
public abstract boolean delete(int id);
public abstract void truncate();
public abstract boolean delete(int[] id);
public abstract List<User> find(String[][] searchPara,Pager pager);
public abstract List<User> find(String[][] searchPara);
}
/*UserDao实现*/
package com.xing.cms.model.dao.impl;
import java.sql.SQLException;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
//import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import com.xing.cms.model.businessobject.User;
import com.xing.cms.model.dao.UserDao;
import com.xing.cms.model.util.GeneralTool;
import com.xing.cms.model.util.Pager;
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
private JdbcTemplate jdbcTemplate;// Spring Injection
public UserDaoImpl() {
super();
}
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate param) {
this.jdbcTemplate = param;
}
@SuppressWarnings("unchecked")
public List<User> find(final String[][] searchPara, final Pager pager) {
return (List<User>) this.getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session)
throws SQLException, HibernateException {
Criteria ca_count = null;
if(pager.isPageAble())
ca_count = session.createCriteria(User.class);//不能避免,需要查询两次数据库,这个获取总数
Criteria ca = session.createCriteria(User.class);
if(searchPara != null){
ca.setProjection(null);
for (int i = 0; i < searchPara.length; i++) {
if (searchPara[i][1].equalsIgnoreCase("=")) {
if(pager.isPageAble())
ca_count.add(Restrictions.eq(searchPara[i][0], searchPara[i][2]));
ca.add(Restrictions.eq(searchPara[i][0], searchPara[i][2]));
} else if (searchPara[i][1].equalsIgnoreCase("like")) {
if(pager.isPageAble())
ca_count.add(Restrictions.like(searchPara[i][0], searchPara[i][2],MatchMode.ANYWHERE));
ca.add(Restrictions.like(searchPara[i][0], searchPara[i][2],MatchMode.ANYWHERE));
}
}
}
List ret_list;
if (pager.isPageAble()) {
pager.setTotalObjects(((Integer) (ca_count
.setProjection(Projections.rowCount())
.uniqueResult())).intValue()); //获取Count
pager.calc();
ca.addOrder(Order.desc("UID"));
ca.setFirstResult(pager.getFirstResult());
ca.setMaxResults(pager.getPageSize());
ret_list = ca.list();
} else {
ca.addOrder(Order.desc("UID"));
ret_list = ca.list();
}
return ret_list;
}
});
}
// ......其它方法略去
/*测试类*/
package test;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;
import com.xing.cms.model.businessobject.User;
import com.xing.cms.model.dao.DocumentDao;
import com.xing.cms.model.dao.UserDao;
import com.xing.cms.model.util.HtmlGenerator;
import com.xing.cms.model.util.Pager;
import com.xing.cms.model.util.UtilXml;
import com.xing.cms.action.UserAction;
public class TestSpring extends AbstractTransactionalDataSourceSpringContextTests
{
private Log logger = LogFactory.getLog(TestSpring.class);
public String[] getConfigLocations() {
String[] config = new String[]{"applicationContext.xml"};
return config;
}
public void testUserAction() throws Exception{
UserDao dao = (UserDao)applicationContext.getBean("userDao");
assertTrue(dao!=null);
User user = (User)applicationContext.getBean("user");
assertTrue(user!=null);
Pager pager = (Pager)applicationContext.getBean("pager");
assertTrue(pager!=null);
UserAction action = (UserAction)applicationContext.getBean("userAction");
assertTrue(action!=null);
//clear all first
dao.truncate();
//super.setComplete();
//add
for(int i=0;i<20;i++)
{
User u = new User();
u.setGID(1);
u.setUsername("xzw_"+i);
u.setPassword("abcd");
dao.save(u);
}
//no pager
/*
assertEquals(0,dao.find(
new String[][]{
new String[]{"username","=","xzw"}
}
).size());
assertEquals(20,dao.find(null).size());
*/
//with pager
//action.getPager().setPageSize(9);
//10 11 12 ... 19 + 1 = 11
/*分页,取第一页,前4 条,应该返回4*/
action.getPager().setPageSize(4);
assertEquals(4,dao.find(new String[][]{
new String[]{"username","like","xzw_1"}
},action.getPager()).size());
/*不分页,则取全部的,应该返回20*/
action.getPager().setPageAble(false);
action.getPager().setPageSize(4);
assertEquals(11,dao.find(new String[][]{
new String[]{"username","like","xzw_1"}
},action.getPager()).size());
}
}
Posted by kevinwu 11:33 PM | 全文 | 评论 (0) | SPRING(24)
Spring+hibernate分页查询
/**
* TOP查询
* @param sql String
* @param top int
* @return List
*/
public List findTop(String sql, int top) {
HibernateTemplate ht = this .getHibernateTemplate();
ht.setMaxResults(top);
return ht.find(sql);
}
/**
* 分页查询
* @param sql String
* @param firstRow int
* @param maxRow int
* @return List
*/
public List findPage( final String sql, final int firstRow, final int maxRow) {
return this .getHibernateTemplate().executeFind( new HibernateCallback(){
public Object doInHibernate(Session session) throws SQLException,
HibernateException {
Query q = session.createQuery(sql);
q.setFirstResult(firstRow);
q.setMaxResults(maxRow);
return q.list();
}
});
}
模板实现分页:
public List find( final String hsql, final int firstRow, final int maxRow) throws Exception {
return getHibernateTemplate().executeFind( new HibernateCallback() {
public Object doInHibernate(Session s) throws HibernateException, SQLException {
Query query = s.createQuery(hsql);
query.setFirstResult(firstRow);
query.setMaxResults(maxRow);
List list = query.list();
return list;
}
});
}
Posted by kevinwu 11:31 PM | 全文 | 评论 (0) | SPRING(24)
hibernate+spring的一个简单分页实现
Spring DAO的编写:
利用hibernate提供的Query的setFirstResult和setMaxResults方法进行数据分页,程序中以我建立的用户表为例,query的分页机制是以跳指针的方式进行数据读取,这样极大的提高的数据分页程序的响应速度
//分页主程序
public List getUsersPage(int firstResults,int maxResults){
try {
Session session=this.getSession();
Query query=session.createQuery("from SYSUSERS sysusers order by sysusers.username asc");
query.setFirstResult(firstResults);
query.setMaxResults(maxResults);
return query.list();
} catch (HibernateException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
finally{
try {
session.close();
} catch (HibernateException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
}
return null;
}
//显示分页总页数
public String getPageCount(int maxResults){
String pageCount="0";
try {
session=this.getSession();
Query query=session.createQuery("select count(sysusers.id) from SYSUSERS sysusers");
int Count=((Integer)query.list().get(0)).intValue();
if(Count%maxResults>0){
pageCount=String.valueOf(Count/maxResults+1);
}
else{
pageCount=String.valueOf(Count/maxResults);
}
return String.valueOf(pageCount);
} catch (HibernateException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
finally{
try {
session.close();
} catch (HibernateException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
}
return pageCount;
}
//显示总记录数
public String getTotalMark(){
String totalMark="0";
try {
session=this.getSession();
Query query=session.createQuery("select count(sysusers.id) from SYSUSERS sysusers");
int Count=((Integer)query.list().get(0)).intValue();
totalMark=String.valueOf(Count);
return totalMark;
} catch (HibernateException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
finally{
try {
session.close();
} catch (HibernateException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
}
return totalMark;
}
写完spring的dao之后定义相应的接口,这里不在复述
在这个dao写好之后,就可以在相应的表示层中进行方法调用,达到分页的目的