分页查询
分页查询简介
当一个操作数据库进行查询的语句返回的结果集内容如果过多,那 么内存极有可能溢出,所以在查询中含有大数据的情况下分页是必 须的。
分页查询分类:
物理分页:
在数据库执行查询时(实现分页查询),查询需要的数据—依赖数据库的SQL语句
在SQL查询时,从数据库只检索分页需要的数据
通常不同的数据库有着不同的物理分页语句
MySql物理分页采用limit关键字
逻辑分页:
在sql查询时,先从数据库检索出所有数据的结果集,在程序内,通过逻辑语句获得分页需要的数 据
如何在MySql中实现物理分页查询
使用limit方式。
limit的使用
select * from tableName limit m,n
其中m与n为数字。n代表需要获取多少行的数据项,而m代表从哪 开始(以0为起始)。
例如我们想从users表中先获取前两条数据SQL为:
select * from users limit 0,2;
那么如果要继续看下两条的数据则为:
select * from users limit 2,2;
以此类推 分页公式:(当前页-1)*每页大小
创建Page模型
Page
/** * 分页查询实体类 */ public class Page<T> { //当前页 private int currentPage; //每页显示的条数 private int pageSize; //总条数 private int totalCount; //总页数 private int totalPage; //结果集 private List<T> result; public int getCurrentPage() { return currentPage; } public void setCurrentPage(int currentPage) { this.currentPage = currentPage; } public int getPageSize() { return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } public int getTotalCount() { return totalCount; } public void setTotalCount(int totalCount) { this.totalCount = totalCount; } public int getTotalPage() { return totalPage; } public void setTotalPage(int totalPage){ this.totalPage = totalPage; } public List<T> getResult() { return result; } public void setResult(List<T> result) { this.result = result; } }
实现分页查询
分页实现
/** * 分页查询测试类 */ public class PageTest { /** * 分页查询Users */ public Page<Users> selectPage(Page page) { Connection conn =null; PreparedStatement ps = null; ResultSet rs = null; List<Users> list = new ArrayList<>(); try{ //获取连接对象 conn = JdbcUtils.getConnection(); //创建PrepareStatement对象 ps = conn.prepareStatement("select * from users limit ?,?"); //绑定m参数 m的值 = (当前页-1)*每页显示的条数 ps.setInt(1, (page.getCurrentPage()-1)*page.getPageSize()); //绑定n参数 n的值为每页显示的条数 ps.setInt(2,page.getPageSize()); //执行查询 rs = ps.executeQuery(); //处理结果集 while(rs.next()){ //完成ORM映射 Users users = new Users(); users.setUserid(rs.getInt("userid")); users.setUsername(rs.getString("username")); users.setUserage(rs.getInt("userage")); list.add(users); } //讲结果集存放到Page对象中。 page.setResult(list); //查询总条数 ps =conn.prepareStatement("select count(*) from users"); //执行查询 rs = ps.executeQuery(); while(rs.next()){ //总条数 int count = rs.getInt(1); //保存总条数 page.setTotalCount(count); //换算总页数 = 总条数 / 每页显示的条数 向上取整 int totalPage = (int)Math.ceil(1.0*count/page.getPageSize()); //保存总页数 page.setTotalPage(totalPage); } }catch(Exception e){ e.printStackTrace(); }finally{ JdbcUtils.closeResource(rs,ps,conn); } return page; } public static void main(String[] args) { PageTest pt = new PageTest(); Page page = new Page(); page.setCurrentPage(2); page.setPageSize(2); Page page1 = pt.selectPage(page); System.out.println("总条数:"+page1.getTotalCount()); System.out.println("总页数:"+page1.getTotalPage()); System.out.println("当前页:"+page1.getCurrentPage()); System.out.println("每页显示的条数:"+page1.getPageSize()); List<Users> list =page1.getResult(); for(Users user:list){ System.out.println(user.getUserid()+ " "+user.getUsername()+" "+user.getUserage()); } } }
数据库连接池
数据库连接池简介
什么是数据库连接池
数据库连接池(Connection pooling)是程序启动时建立足够的数 据库连接,并将这些连接组成一个连接池,由程序动态地对池中的 连接进行申请,使用,释放。 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建 立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为 没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提 高对数据库操作的性能。
不使用数据库连接池存在的问题
1、普通的JDBC数据库连接使用 DriverManager 来获取,每次向数 据库建立连接的时候都要将 Connection加载到内存中,再验证 用户名和密码,所以整个过程比较耗时。
2、需要数据库连接的时候,就向数据库要求一个,执行完成后再断 开连接。这样的方式将会消耗大量的资源和时间。数据库的连接 资源并没有得到很好的重复利用。若同时有几百人甚至几千人在 线,频繁的进行数据库连接操作将占用很多的系统资源,严重的甚至会造成服务器的崩溃。
3、对于每一次数据库连接,使用完后都得断开。否则,如果程序出 现异常而未能关闭,将会导致数据库系统中的内存泄漏,最终将 导致重启数据库。
JDBC数据库连接池的必要性
数据库连接池的基本思想:为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连 接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连 接,而不是重新建立一个。
数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由 最小数据库连接数来设定的。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么 多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序 向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。
数据库连接池的优点
1、资源重用:由于数据库连接得以重用,避免了频繁创建,释放连接引起的大量性能开销。在减少系 统消耗的基础上,另一方面也增加了系统运行环境的平稳性。
2、更快的系统反应速度:数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于连接池 中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接避免了 数据库连接初始化和释放过程的时间开销,从而减少了系统的响应时间。
3、新的资源分配手段:对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接池的配置 实现某一应用最大可用数据库连接数的限制避免某一应用独占所有的数据库资源。
4、统一的连接管理:避免数据库连接泄露在较为完善的数据库连接池实现中,可根据预先的占用超时 设定,强制回收被占用连接,从而避免了常规数据库连接操作中可能出现的资源泄露。
常用的数据库连接池
c3p0:是一个开源组织提供的数据库连接池,速度相对较慢,稳定性还可以。
DBCP:是Apache提供的数据库连接池。速度相对c3p0较快,但自身存在bug。
Druid:是阿里提供的数据库连接池,据说是集DBCP、c3p0优点于一身的数据库连接池,目前经 常使用。
Druid连接池
Druid简介
Druid是阿里提供的数据库连接池,它结合了C3P0、DBCP等DB池 的优点,同时加入了日志监控,可以很好的监控DB池连接和SQL的 执行情况。
Druid使用步骤
1 导入druid-1.2.8.jar包到lib目录下,并引入到项目中
2 在src下创建一个druid.properties类型的文件,并写入
3 加载配置文件
4 获取连接池对象
5 通过连接池对象获取连接
url=jdbc:mysql://localhost:3306/itbz driverClassName=com.mysql.jdbc.Driver username=root password=。。。。 initialSize=10 maxActive=20
druid配置信息:
通过数据库连接池获取连接
/** * Druid连接池测试类 */ public class DruidTest { public static void main(String[] args) throws Exception { //获取读取druid配置的字节输入流 InputStream is = DruidTest.class.getClassLoader().getResourceAsStream("druid.properties"); //创建Properties对象 Properties pos = new Properties(); //加载配置文件 pos.load(is); //获取连接池对象 DataSource ds = DruidDataSourceFactory.createDataSource(pos); //获取连接 Connection connection = ds.getConnection(); System.out.println(connection); } }
封装工具类
/** * 基于Druid连接池获取数据库连接工具类 */ public class JdbcDruidUtil { //数据库连接池对象 private static DataSource dataSource; static{ try { //获取读取配置文件的字节输入流对象 InputStream is = JdbcDruidUtil.class.getClassLoader().getResourceAsStream("druid.properties"); //创建Properties对象 Properties pop = new Properties(); //加载配置文件 pop.load(is); //创建连接池对象 dataSource = DruidDataSourceFactory.createDataSource(pop); }catch(Exception e){ e.printStackTrace(); } } //获取数据库连接对象 public static Connection getConnection() { Connection connection = null; try { connection = dataSource.getConnection(); } catch (SQLException throwables) { throwables.printStackTrace(); } return connection; } //关闭连接对象 public static void closeConnection(Connection connection){ try { connection.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } //提交事务 public static void commit(Connection connection){ try { connection.commit(); } catch (SQLException throwables) { throwables.printStackTrace(); } } //事务回滚 public static void rollback(Connection connection){ try { connection.rollback(); } catch (SQLException throwables) { throwables.printStackTrace(); } } //关闭Statement对象 public static void closeStatement(Statement statement){ try { statement.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } //关闭ResultSet public static void closeResultSet(ResultSet resultSet) { try { resultSet.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } //DML操作时关闭资源 public static void closeResource(Statement statement,Connection connection){ //先关闭Statement对象 closeStatement(statement); //在关闭Connection对象 closeConnection(connection); } //查询时关闭资源 public static void closeResource(ResultSet resultSet,Statement statement,Connection connection){ //先关闭ResultSet closeResultSet(resultSet); //在闭Statement对象 closeStatement(statement); //最后关闭Connection对象 closeConnection(connection); } }
通过druid重构JDBCUtils
1 创建JDBCUtilsDruid类
2 使用静态块初始化连接池
public class JDBCUtilsDruid { private static DataSource ds = null; static{ try { InputStream is = JDBCUtilsDruid.class.getClassLoader().getResourceAsStream("druid.properties"); Properties properties = new Properties(); pros.load(is); ds = DruidDataSourceFactory.createDataSource(properties); } catch (Exception e) { e.printStackTrace(); } }
JDBC技术【分页查询、数据库连接池、应用程序分层、封装通用的BaseDao】(四)-全面详解(学习总结---从入门到深化)(中):https://developer.aliyun.com/article/1419275