- 浏览: 27750 次
- 性别:
- 来自: 成都
最新评论
Title:分页的扩展
持久层对于分页功能的缺少,显然是不能接受,为弥补这个不足,我做了分页的扩展,如下:
ExpPublicDao.java
此类继承了PublicDao,作为对分页扩展,比较简单,共四个方法createPageSql,getSqlServerPageSql,getMysqlPageSql,executeSql。
其中createPageSql方法中根据不同数据库调用不同的构造分页条件的SQL的方法;
executeSql方法为查询总记录数的方法,用于分页时计算总页数、以及构造分页条件;
这个类提供了对SQLServer(getSqlServerPageSql)和MySql(getMysqlPageSql)数据库的分页支持,我本想做一个通用方法,兼容各类数据库,但是由于个数据库间的数据库语法差异,执行效率还不如分开来好。两者分页方案一致,如下:
基于这个分页方案,可以扩展其他可能用到的数据库分页方法。
并且由于数据库差异,DBConnect也应同步一致。在没有使用多数据源的情况下,编写一个兼容各数据库的方法显得毫无意义。
==========================================
有了分页的持久层支持,还需要一个负责传递分页信息的中间对象,如下:
page.java
仔细看,page中就这一部分,包含了实现分页的基本信息,这个也是可以扩展的:
同时,在给总记录数recordCount赋值的时候,总页数pageCount也被赋值了,如下:
还是以role表为例,简单测试:
这里得到SQL:
先到数据库里查询一下:
得到数据集之后,在解析它,再封装为以role对象为内容的数据结构,解析办法如下:
看图看真相:
总结,对于返回的数据结构,可以自定义,方式方法很多,但最终目的是如何方便的使用查询得到的数据,而不用考虑数据怎么来的,这就是持久层存在的意义
持久层对于分页功能的缺少,显然是不能接受,为弥补这个不足,我做了分页的扩展,如下:
ExpPublicDao.java
package com.pub.dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Map; import com.pub.db.DBConnection; import com.pub.page.Page; /*** * 扩展PublicDao,处理分页Sql * @author Administrator * */ public class ExpPublicDao extends PublicDao { /*** * 构造方法 */ public ExpPublicDao(){ super(); } /***【重】【增】 * 构造分页sql语句专用方法 * 分页查询可以不考虑操作类型,所以减少了操作类型的参数type * 同时基于Page对象,在Page中做了表名、主键的记录,这里可以减少表名这个参数 * @param type * @param page * @param mk * @param mv * @return */ public String createPageSql(Map<Object, String> mk,Map<Object, Object> mv, String condition, Page page){ StringBuffer sql = new StringBuffer(); //接收查询部分 sql.append(this.createSql(PublicDao.SELECT, page.getTableName(), mk, mv, condition)); //SQL条件部分 StringBuffer where = new StringBuffer(); //在查询状态下,通过mv判断条件不为空 if(mv.size() > 0 ){//配置条件部分 where.append(" where 1=1 and "); if("".equals(condition) || null == condition){ for(int i=1;i<=mv.size();i++){ where.append(mv.get(i)); if(i != mv.size()){ where.append(" and "); } } }else{ for(int i=1;i<=mv.size();i++){ where.append(mv.get(i)+""+condition.split(", ")[i-1]);//逗号+空格 if(i != mv.size()){ where.append(" and "); } } } return this.getMysqlPagerSql(sql, page, where).toString(); }else{//条件为空 return this.getMysqlPagerSql(sql, page, where).toString(); } } /*** * 构造SqlServer分页Sql * @param sql * @param page * @param where * @return getSqlServerPagerSql */ public StringBuffer getSqlServerPagerSql(StringBuffer sql, Page page, StringBuffer where){ //添加 sql = new StringBuffer(sql.toString().replaceFirst("select", "select top "+page.getPageSize()+" ")); StringBuffer condition = new StringBuffer(); //当前页为第1页 if(page.getCurrentPage() <= 1){ if(page.getCurrentPage() < 1){ page.setCurrentPage(1); } condition.append(" ORDER BY " + page.getPrimaryKey()); }else{//当前页不为第1页 if(page.getCurrentPage() > page.getPageCount()){ if(page.getPageCount() <= 1){ page.setCurrentPage(1); getSqlServerPagerSql(sql, page, where); return sql; } //为便于测试,保证运行,判断当总页数小于当前页数的时候设置当前页为总页数 page.setCurrentPage(page.getPageCount()); } //对于分页的条件部分,拼凑SQL语句不算复杂 condition.append(" where "+page.getPrimaryKey() + " > (SELECT MAX(" + page.getPrimaryKey() + ") "+ " FROM (SELECT TOP "+(page.getCurrentPage()-1)*page.getPageSize()+" " + page.getPrimaryKey() + " "+ " FROM " + page.getTableName() + " @where ORDER BY " + page.getPrimaryKey() + ") AS T) "+ "ORDER BY " + page.getPrimaryKey() ); } // 最后,替换条件子查询中条件占位符 sql = sql.append(condition.toString().replace("@where", (where == null || where.equals(""))?"":where)); return sql; } /*** * 构造Mysql分页Sql * @param sql * @param page * @param where * @return */ public StringBuffer getMysqlPagerSql(StringBuffer sql, Page page, StringBuffer where){ StringBuffer condition = new StringBuffer(); if(page.getCurrentPage() <= 1){ if(page.getCurrentPage() < 1){ page.setCurrentPage(1); } condition.append(" ORDER BY " + page.getPrimaryKey()); }else{ if(page.getCurrentPage() > page.getPageCount()){ if(page.getPageCount() <= 1){ page.setCurrentPage(1); getMysqlPagerSql(sql, page, where); return sql; } //为便于测试,保证运行,判断当总页数小于当前页数的时候设置当前页为总页数 page.setCurrentPage(page.getPageCount()); } //构造条件 condition.append(" where "+page.getPrimaryKey() + " > (SELECT MAX(" + page.getPrimaryKey() + ") "+ " FROM (SELECT " + page.getPrimaryKey() + " "+ " FROM " + page.getTableName() + " @where ORDER BY " + page.getPrimaryKey() + " LIMIT "+(page.getCurrentPage()-1)*page.getPageSize()+" ) AS T) "+ "ORDER BY " + page.getPrimaryKey() ); } // 最后,替换条件子查询中条件占位符 sql.append(condition.toString().replace("@where", (where == null || where.toString().equals(""))?"":where.toString()) + " LIMIT " + page.getPageSize()); return sql; } /*** * 执行Sql,获取总记录数<br> * @param sql * @return count 总记录数 */ public int executeSql(String sql){ Connection con = //DBConnection.getConnection(); DBConnection.getMySqlConnection(); PreparedStatement ps = null; ResultSet rs = null; try { con = DBConnection.getConnection(); ps = con.prepareStatement(sql); rs = ps.executeQuery(); int count = 0; while(rs.next()){ count ++; } return count; } catch (SQLException e) { e.printStackTrace(); return 0; } finally { close(con, ps, rs); } } }
此类继承了PublicDao,作为对分页扩展,比较简单,共四个方法createPageSql,getSqlServerPageSql,getMysqlPageSql,executeSql。
其中createPageSql方法中根据不同数据库调用不同的构造分页条件的SQL的方法;
executeSql方法为查询总记录数的方法,用于分页时计算总页数、以及构造分页条件;
这个类提供了对SQLServer(getSqlServerPageSql)和MySql(getMysqlPageSql)数据库的分页支持,我本想做一个通用方法,兼容各类数据库,但是由于个数据库间的数据库语法差异,执行效率还不如分开来好。两者分页方案一致,如下:
SELECT TOP 页大小 * FROM TestTable WHERE (ID > (SELECT MAX(id) FROM (SELECT TOP 页大小*页数 id FROM 表 ORDER BY id) AS T)) ORDER BY ID
基于这个分页方案,可以扩展其他可能用到的数据库分页方法。
并且由于数据库差异,DBConnect也应同步一致。在没有使用多数据源的情况下,编写一个兼容各数据库的方法显得毫无意义。
==========================================
有了分页的持久层支持,还需要一个负责传递分页信息的中间对象,如下:
page.java
package com.pub.page; /*** * Page对象 * 设置表名、主键字段名,用于拼接分页Sql字符串,也可以通过Pojo中指定 * @author Administrator * 2011-05-11 */ public class Page { /**当前页*/ private int currentPage; /**总页数*/ private int pageCount; /**每页的记录条数*/ private int pageSize; /**总的记录条数*/ private int recordCount; /**表名*/ private String tableName; /**主键字段名*/ private String primaryKey; /**数据库*/ private String DataBaseName; /*** * 获取主键字段名 * @return */ public String getPrimaryKey() { return primaryKey; } public void setPrimaryKey(String primaryKey) { this.primaryKey = primaryKey; } /*** * 获取表名 * @return */ public String getTableName() { return tableName; } public void setTableName(String tableName) { this.tableName = tableName; } /*** * 当前页 * @return */ public int getCurrentPage() { if(currentPage <= 0){ this.setCurrentPage(1); } return currentPage; } public void setCurrentPage(int currentPage) { this.currentPage = currentPage; } /*** * 总页数 * @return */ public int getPageCount() { return pageCount; } public void setPageCount(int pageCount) { this.pageCount = pageCount; } /*** * 获取页显示记录数大小,默认为10 * @return */ public int getPageSize() { if(pageSize <= 0){ this.setPageSize(10); } return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } /*** * 总记录数 * @return */ public int getRecordCount() { return recordCount; } /*** * 设置总记录数,同时设置总页数 * @param recordCount */ public void setRecordCount(int recordCount) { this.setPageCount( recordCount%this.getPageSize() != 0 ? recordCount/this.getPageSize()+1 : recordCount/this.getPageSize() ); this.recordCount = recordCount; } public String getDataBaseName() { if(DataBaseName == null || DataBaseName.equals("")){ return "SQLSERVER"; } return DataBaseName; } public void setDataBaseName(String dataBaseName) { DataBaseName = dataBaseName; } }
仔细看,page中就这一部分,包含了实现分页的基本信息,这个也是可以扩展的:
/**当前页*/ private int currentPage; /**总页数*/ private int pageCount; /**每页的记录条数*/ private int pageSize; /**总的记录条数*/ private int recordCount; /**表名*/ private String tableName; /**主键字段名*/ private String primaryKey; /**数据库*/ private String DataBaseName;
同时,在给总记录数recordCount赋值的时候,总页数pageCount也被赋值了,如下:
/*** * 设置总记录数,同时设置总页数 * @param recordCount */ public void setRecordCount(int recordCount) { this.setPageCount( recordCount%this.getPageSize() != 0 ? recordCount/this.getPageSize()+1 : recordCount/this.getPageSize() ); this.recordCount = recordCount; }
还是以role表为例,简单测试:
ExpPublicDao dao = new ExpPublicDao(); Page page = new Page(); page.setTableName("role"); page.setPrimaryKey(Role.getPrimaryKey()); page.setCurrentPage(2); page.setPageSize(5); //这里为了方便,就手写SQL代码啦,实际调用不会这样哈 page.setRecordCount(dao.executeSql("select * from role")); Map<Object, String> mk = new HashMap<Object, String>(); Map<Object, Object> mv = new HashMap<Object, Object>(); //设置要查询的列 mk.put(1, Role.RoleId()); mk.put(2, Role.RoleLevel()); mk.put(3, Role.RoleName()); mk.put(4, Role.RoleResource()); mk.put(5, Role.Remark()); String sql = dao.createPageSql(mk, mv, "", page); System.out.println(sql); //执行获得数据集 List list = dao.executeSql(PublicDao.SELECT, sql);
这里得到SQL:
SELECT role_id,role_level,role_name,role_resource,remark FROM role WHERE role_id > (SELECT MAX(role_id) FROM ( SELECT role_id FROM role ORDER BY role_id LIMIT 5 ) AS T ) ORDER BY role_id LIMIT 5
先到数据库里查询一下:
得到数据集之后,在解析它,再封装为以role对象为内容的数据结构,解析办法如下:
//执行获得数据集 List list = dao.executeSql(PublicDao.SELECT, sql)//接上 /**用于封装并返回数据的集合对象*/ List<Role> list_t = new ArrayList<Role>(); //取出列名Map Map mk_n = (Map) list.get(0); //取出每一行数据 List list_mv = (List) list.get(1); //封装的对象 Role role = null; for(int i=0;i<list_mv.size();i++){ Map mv_n = (Map) list_mv.get(i); //这里每循环一次代表每一行数据,即一个对象 role = new Role(); for(int j=1;j<=mk_n.size();j++){ Object temp = mv_n.get(mk_n.get(j)); if(Role.RoleId().equals(mk_n.get(j))){ role.setRoleId(temp==null?null:(Integer)temp); } if(Role.RoleName().equals(mk_n.get(j))){ role.setRoleName(temp==null?"":temp.toString()); } if(Role.RoleResource().equals(mk_n.get(j))){ role.setRoleResource(temp==null?"":temp.toString()); } if(Role.RoleLevel().equals(mk_n.get(j))){ role.setRoleLevel(temp==null?"":temp.toString()); } } list_t.add(role); }
看图看真相:
总结,对于返回的数据结构,可以自定义,方式方法很多,但最终目的是如何方便的使用查询得到的数据,而不用考虑数据怎么来的,这就是持久层存在的意义
相关推荐
标题 "钢炮级 持久层 —— 中篇" 提到的是关于持久层技术的深入探讨,这通常指的是在软件开发中用于处理数据库交互的框架或库。持久层是应用程序与数据库之间的桥梁,它负责数据的存储和检索,使得业务逻辑与数据...
《小钢炮蓝牙音箱PADS9.5设计详解——硬件原理与PCB解析》 在电子设备领域,蓝牙音箱凭借其无线便捷性受到广大消费者的喜爱。"小钢炮"蓝牙音箱,以其小巧便携、音质出色的特点,成为市场上的一款热门产品。本资料...
在介绍MicroPython读取小钢炮开发板上的HTS221温湿度传感器的文章中,我们首先需要了解HTS221传感器的基本信息。HTS221是一款由STMicroelectronics生产的数字输出相对湿度和温度传感器,该传感器能够提供高精度的...
Skylake平台小钢炮Z170芯片组ITX主板.pdf
在本项目中,我们关注的是使用PADS 9.5软件进行小钢炮蓝牙音箱的BGA(Ball Grid Array)两层板设计。这涉及到电子工程中的多个关键知识点,包括硬件设计、电路板布局、BGA封装处理以及PCB设计流程。 首先,硬件设计...
市场上各种蓝牙音箱数不胜数,小钢炮系列的蓝牙音箱也颇受欢迎。 这个是我收集的蓝牙音箱原理图和PCB,之所有拿出来分享,这个PCB是两层板,但是包含了BGA封装的蓝牙模块,layout的...PCB是两层板,也省下了一笔成本。
基于PADS9.5设计的小钢炮蓝牙音箱硬件(原理图+PCB)文件+RDA58硬件应用指南,可供学习及设计参考。
2.5寸硬盘抽取式机箱DWG图 大小: 101103 字节 MD5: A5972B2DC6CD17A6D0169A02BB7B6AC8 SHA1: B11C8ED0B7A7AD9D655554B4FB65B0257E8D1758
描述中提到的“小钢炮 I7-8850H,UHD 630黑苹果10.14.4成功”,意味着有人成功地在配备 i7-8850H 和 UHD 630 显卡的紧凑型高性能电脑(可能指小型台式机或笔记本电脑)上安装了 macOS 10.14.4,并且提供了详细的教程...
【Huan】_高CP值的小鋼砲組合!_全漢FSP_CST350機殼+金鋼彈850W_SFX電源開箱_FSP_CST350_Cas
在Windows环境下编译STM32的Micropython固件时,需要注意gcc编译器路径是否已经添加到系统路径中。如果未添加且不希望修改makefile文件,可以在编译时输入命令: ``` make CROSS_COMPILE=e:/gcc-arm/bin/arm-none-...
MyBatis则是一个轻量级的持久层框架,实现了SQL语句与Java代码的解耦。 二、前端设计 1. HTML5与CSS3:项目采用现代Web技术,提供响应式布局,确保在不同设备上都能良好显示。 2. Bootstrap框架:用于快速构建美观...
在本项目中,我们将基于开源电子网的官方库函数,通过串口打印HTS221所测得的温湿度值,并利用小钢炮开发板进行IIC通信,以16MHz的晶振频率为系统提供时钟支持。 首先,我们需要了解HTS221的基本特性。这款传感器...
Hibernate作为持久层框架,简化了数据库操作。它提供了对象关系映射(Object-Relational Mapping,ORM),使得开发人员可以使用面向对象的方式处理数据库事务,而无需编写大量的SQL语句。Hibernate支持事务管理,...
直接驱动小米所有蓝牙设备~ 找了很久,只有这个才真正有用~
Kali for Android 是一种将 Kali 系统安装到安卓设备上的解决方案,将安卓设备变成渗透测试小钢炮。以下是实现 Kali for Android 的详细步骤和知识点: 一、前提条件 * 安卓设备已经获取了 root 权限 * 安卓设备...
研究目的 主要研究内容是基于多目相机,利用图像拼接技术...摄像头:采用淘宝上最便宜的小钢炮摄像头,单个价格25元左右 摄像头固定装置:计算摄像头的视场,使用Autodesk 3ds Max设计固定装置,并使用3D打印技术打印
2. **细分市场多样化**:除了传统的车型之外,本次车展还展示了多款针对特定细分市场设计的新车型,例如A00级敞篷车(五菱宏光MINIEV敞篷版)、两厢钢炮(第八代高尔夫GTI、领克02 Hatchback)、敞篷跑车(MG ...
4. 开标后,遵循最低价中标原则,但在满足招标方所有需求的前提下。 5. 中标单位拒签合同或提出重大修改将导致投标保证金被没收。 【合同签订】 中标单位将与贺兰县农村信用合作联社签订为期两年的《贺兰联社办公...
此外,小众细分市场的新车如A00级敞篷车、两厢钢炮、敞篷跑车、豪华SUV和乘用化皮卡等也吸引了不少关注。 新品牌和新标识的出现是本次车展的另一大亮点。长城汽车的坦克品牌独立,上汽智己、吉利极氪首次参展,现代...