JDBC技术【分页查询、数据库连接池、应用程序分层、封装通用的BaseDao】(四)-全面详解(学习总结---从入门到深化)(上)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: JDBC技术【分页查询、数据库连接池、应用程序分层、封装通用的BaseDao】(四)-全面详解(学习总结---从入门到深化)

分页查询



分页查询简介


当一个操作数据库进行查询的语句返回的结果集内容如果过多,那 么内存极有可能溢出,所以在查询中含有大数据的情况下分页是必 须的。


分页查询分类:


物理分页:


在数据库执行查询时(实现分页查询),查询需要的数据—依赖数据库的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

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
目录
相关文章
|
3月前
|
存储 关系型数据库 数据库
附部署代码|云数据库RDS 全托管 Supabase服务:小白轻松搞定开发AI应用
本文通过一个 Agentic RAG 应用的完整构建流程,展示了如何借助 RDS Supabase 快速搭建具备知识处理与智能决策能力的 AI 应用,展示从数据准备到应用部署的全流程,相较于传统开发模式效率大幅提升。
附部署代码|云数据库RDS 全托管 Supabase服务:小白轻松搞定开发AI应用
|
4月前
|
安全 druid Nacos
0 代码改造实现应用运行时数据库密码无损轮转
本文探讨了敏感数据的安全风险及降低账密泄漏风险的策略。国家颁布的《网络安全二级等保2.0标准》强调了企业数据安全的重要性。文章介绍了Nacos作为配置中心在提升数据库访问安全性方面的应用,并结合阿里云KMS、Druid连接池和Spring Cloud Alibaba社区推出的数据源动态轮转方案。该方案实现了加密配置统一托管、帐密全托管、双层权限管控等功能,将帐密切换时间从数小时优化到一秒,显著提升了安全性和效率。未来,MSE Nacos和KMS将扩展至更多组件如NoSQL、MQ等,提供一站式安全服务,助力AI时代的应用安全。
277 14
|
24天前
|
存储 弹性计算 Cloud Native
云原生数据库的演进与应用实践
随着企业业务扩展,传统数据库难以应对高并发与弹性需求。云原生数据库应运而生,具备计算存储分离、弹性伸缩、高可用等核心特性,广泛应用于电商、金融、物联网等场景。阿里云PolarDB、Lindorm等产品已形成完善生态,助力企业高效处理数据。未来,AI驱动、Serverless与多云兼容将推动其进一步发展。
93 8
|
13天前
|
存储 弹性计算 安全
现有数据库系统中应用加密技术的不同之处
本文介绍了数据库加密技术的种类及其在不同应用场景下的安全防护能力,包括云盘加密、透明数据加密(TDE)和选择列加密。分析了数据库面临的安全威胁,如管理员攻击、网络监听、绕过数据库访问等,并通过能力矩阵对比了各类加密技术的安全防护范围、加密粒度、业务影响及性能损耗。帮助用户根据安全需求、业务改造成本和性能要求,选择合适的加密方案,保障数据存储与传输安全。
|
3月前
|
安全 Java Nacos
0代码改动实现Spring应用数据库帐密自动轮转
Nacos作为国内被广泛使用的配置中心,已经成为应用侧的基础设施产品,近年来安全问题被更多关注,这是中国国内软件行业逐渐迈向成熟的标志,也是必经之路,Nacos提供配置加密存储-运行时轮转的核心安全能力,将在应用安全领域承担更多职责。
|
2月前
|
存储 人工智能 数据库
视图是什么?为什么要用视图呢?数据库视图:定义、特点与应用
本文三桥君深入探讨数据库视图的概念与应用,从定义特点到实际价值全面解析。视图作为虚拟表具备动态更新、简化查询、数据安全等优势,能实现多角度数据展示并保持数据库重构的灵活性。产品专家三桥君还分析了视图与基表关系、创建维护要点及性能影响,强调视图是提升数据库管理效率的重要工具。三桥君通过系统讲解,帮助读者掌握这一常被忽视却功能强大的数据库特性。
404 0
|
11月前
|
Java 数据库连接 测试技术
SpringBoot入门 - 添加内存数据库H2
SpringBoot入门 - 添加内存数据库H2
651 3
SpringBoot入门 - 添加内存数据库H2
|
4月前
|
存储 数据库连接 数据库
告别数据库瓶颈!用这个技巧让你的程序跑得飞快!
本文介绍了数据库连接池的概念及其在性能优化中的重要性,通过两个示例展示了如何管理 SQLite 数据库连接。首先,手动实现了一个基于 `sqlite3` 和 `queue.Queue` 的简单连接池,涵盖初始化、获取与释放连接的核心流程。接着,使用功能更强大的 `SQLAlchemy` 库创建连接池,简化了连接管理并支持更多高级特性。对比两种方式后发现,自定义连接池适合学习和小型应用,而 `SQLAlchemy` 更适用于复杂场景。合理使用连接池可显著提升高并发环境下的数据库操作效率。
76 1
|
4月前
|
SQL 数据库
软考软件评测师——数据库系统应用
本文介绍了关系数据库的基础知识与应用,涵盖候选码定义、自然连接特点、实体间关系(如1:n和m:n)、属性分类(复合、多值与派生属性)以及数据库设计规范。同时详细解析了E-R图转换原则、范式应用(如4NF)及Armstrong公理体系。通过历年真题分析,结合具体场景(如银行信用卡额度、教学管理等),深入探讨了候选键求解、视图操作规范及SQL语句编写技巧。内容旨在帮助读者全面掌握关系数据库理论与实践技能。