创新实训——数据库连接池的实现(一)

项目实训(十三)数据库连接池的实现 1.为什么需要数据库连接池: 数据库连接是一种关键的、有限的、昂贵的资源。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标。数据库连接池正是针对这个问题提出来的。 数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏... 阅读详情

1.为什么需要数据库连接池:

数据库连接是一种关键的、有限的、昂贵的资源。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标。数据库连接池正是针对这个问题提出来的。

数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。

常见的数据库连接池有:dbcp、cp30、druid。其中Druid是阿里巴巴开源平台上一个数据库连接池实现,是“Java语言中最好的数据库连接池”。Druid能够提供强大的监控和扩展功能。源码地址:https://github.com/alibaba/druid。

2.实现自己的数据库连接池

参考okhttp3的ConnectionPool以及RealConnection的实现,学习okhttp3网络连接池的思想,实现数据库连接池。

ConnectionPool维护一个RealConnection的列表。

在增加新的连接时会清除空闲时间超过最大空闲时间的连接,保证资源的有效回收和内存的高效利用。

在提供连接是会返回负载最低的连接,保证所有连接的负载均衡。

public final class ConnectionPool {
    private final Deque<RealConnection> connections = new ArrayDeque<>();

    private static final Executor executor = new ThreadPoolExecutor(
            0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
            new SynchronousQueue<Runnable>());

    private final int maxIdleConnections;
    private final int corePoolSize;
    private final long keepAliveDurationNs;
    private boolean cleanupRunning;

    public ConnectionPool() {
        this(5, 5, 10, TimeUnit.MINUTES);
    }

    public ConnectionPool(int corePoolSize, int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit) {
        this.corePoolSize = corePoolSize;
        this.maxIdleConnections = maxIdleConnections;
        this.keepAliveDurationNs = timeUnit.toNanos(keepAliveDuration);
        for (int i = 0; i < corePoolSize; i++) {
            connections.add(new RealConnection());
        }
        if (keepAliveDuration <= 0) {
            throw new IllegalArgumentException("keepAliveDuration <= 0: " + keepAliveDuration);
        }
    }

    public synchronized int idleConnectionCount() {
        int total = 0;
        for (RealConnection connection : connections) {
            if (connection.getCount() <= 0) total++;
        }
        return total;
    }

    public synchronized int connectionCount() {
        return connections.size();
    }

    @Nullable
    RealConnection get() {
        if (connections.size() < corePoolSize || connections.isEmpty()) {
            RealConnection connection = new RealConnection();
            put(connection);
            return connection;
        }
        int minCount = Integer.MAX_VALUE;
        RealConnection minCountConnection = connections.getFirst();
        for (RealConnection connection : connections) {
            if (connection.getCount() < minCount) {
                minCount = connection.getCount();
                minCountConnection = connection;
            }
        }
        return minCountConnection;
    }

    void put(RealConnection connection) {
        if (!cleanupRunning) {
            cleanupRunning = true;
            executor.execute(cleanupRunnable);
        }
        connections.add(connection);
    }

    boolean connectionBecameIdle(RealConnection connection) {
        if (connection.getCount() <= 0 || maxIdleConnections == 0) {
            connection.close();
            connections.remove(connection);
            return true;
        } else {
            notifyAll();
            return false;
        }
    }

    public void evictAll() {
        synchronized (this) {
            for (Iterator<RealConnection> i = connections.iterator(); i.hasNext(); ) {
                RealConnection connection = i.next();
                if (connection.getCount() <= 0) {
                    connection.close();
                    i.remove();
                }
            }
        }
    }

    long cleanup(long now) {
        int inUseConnectionCount = 0;
        int idleConnectionCount = 0;
        RealConnection longestIdleConnection = null;
        long longestIdleDurationNs = Long.MIN_VALUE;

        // Find either a connection to evict, or the time that the next eviction is due.
        synchronized (this) {
            for (Iterator<RealConnection> i = connections.iterator(); i.hasNext(); ) {
                RealConnection connection = i.next();

                // If the connection is in use, keep searching.
                if (connection.getCount() > 0) {
                    inUseConnectionCount++;
                    continue;
                }
                idleConnectionCount++;
                // If the connection is ready to be evicted, we're done.
                long idleDurationNs = now - connection.getIdleAtNanos();
                if (idleDurationNs > longestIdleDurationNs) {
                    longestIdleDurationNs = idleDurationNs;
                    longestIdleConnection = connection;
                }
            }

            if (longestIdleDurationNs >= this.keepAliveDurationNs
                    || idleConnectionCount > this.maxIdleConnections) {
                // We've found a connection to evict. Remove it from the list, then close it below (outside
                // of the synchronized block).
                connections.remove(longestIdleConnection);
            } else if (idleConnectionCount > 0) {
                // A connection will be ready to evict soon.
                return keepAliveDurationNs - longestIdleDurationNs;
            } else if (inUseConnectionCount > 0) {
                // All connections are in use. It'll be at least the keep alive duration 'til we run again.
                return keepAliveDurationNs;
            } else {
                // No connections, idle or in use.
                cleanupRunning = false;
                return -1;
            }
        }
        longestIdleConnection.close();
        return 0;
    }

    private final Runnable cleanupRunnable = new Runnable() {
        @Override
        public void run() {
            while (true) {
                long waitNanos = cleanup(System.nanoTime());
                if (waitNanos == -1) return;
                if (waitNanos > 0) {
                    long waitMillis = waitNanos / 1000000L;
                    waitNanos -= (waitMillis * 1000000L);
                    synchronized (ConnectionPool.this) {
                        try {
                            ConnectionPool.this.wait(waitMillis, (int) waitNanos);
                        } catch (InterruptedException ignored) {
                        }
                    }
                }
            }
        }
    };
}

 

MySQL数据库实训:从SQL语法到JDBC连接池的实战避坑指南 数据库作为现代应用的核心组件,其核心功能在于高效、安全地存储和管理结构化数据。其工作原理基于客户端-服务器架构,通过SQL语言进行交互,并依靠事务机制保证数据一致性。掌握数据库技术对于构建稳定、可扩展的应用系统具有重要价值,广泛应用于电商、金融、社交等各类互联网场景。在实际开发中,JDBC连接池是提升数据库访问性能的关键技术,它能有效管理连接资源,避免频繁创建和销毁连接的开销。同时,正确处理时区与字符集配置是保障数据准确性的基础,例如在MySQL中统一使用utf8mb4字符集和Asia/Shanghai时区 阅读详情

相关推荐

数据库实训实战:从环境搭建到应用开发的全链路技能解析

数据库作为现代信息系统的核心组件,其核心价值在于高效、可靠地存储与管理结构化数据。其工作原理基于关系模型与事务处理机制,通过SQL语言实现数据的定义、操作与控制。掌握数据库技术对于构建稳定、可扩展的应用系统至关重要,尤其在数据驱动决策的时代背景下。在实际工程实践中,数据库环境搭建与运维是首要环节,涉及多引擎部署(如MySQL、达梦数据库)、客户端工具(如Navicat)连接配置等基础操作。而数据库连接池技术则是优化应用性能、管理并发访问的关键组件,能有效减少连接创建开销,提升系统吞吐量。这些基础技能与概念,

weixin_30938149的博客 479

ThreadPoolExecutor 核心参数 及 线程添加流程

1、背景: 在《阿里巴巴java开发手册》中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理控制开辟线程的数量;另一方面线程的细节管理交给线程池处理,优化了资源的开销。而线程池不允许使用Executors去创建,而要通过ThreadPoolExecutor方式,这一方面是由于jdk中Executor框架虽然提供了如newFixedThreadPool()、newSingleThreadExecutor()、newCachedThreadPoo.

Sucker的小笔记 645

labview中DAQ采集多个数据通道(温度传感器)(TTL信号的曲轴位置传感器)总结

文章目录前言一、面对的问题篇二、问题解决篇三、后续工作总结 前言 我研一的项目利用labview软件和NI数据采集卡采集发动机传感器的信号然后进行采集,发动机传感器是有很多种的,所以难以避免的需要采集多个通道的传感器信号。 一、面对的问题篇 前篇已经写道我已经将温度传感器的信号采集出来,也可以将其数据进行信号处理,由电压信号转变为温度值。但是想要采集多个通道的信号,加上TTL信号的曲轴位置传感器,我模仿温度传感器采集的程序另加了一个DAQ助手进行采集。也就是如图所示的程序: 但是这个程序不能正常显

xiaobaiwsc的博客 1万+

OkHttp3架构分析

在OkHttp3中,其灵活性很大程度上体现在,可以intercept其任意一个环节,而这个优势便是okhttp3整个请求响应架构体系的精髓所在:Okhttp请求流程在OkHttp3中,每一个请求任务都封装为一个Call,其实现为RealCall。而所有的策略几乎都可以通过OkHttpClient传入所有全局策略与数据,除了存储在允许上层访问的OkHttpClient实例以外,还有一部分是存储在只允...

superviser3000的博客 365

Sigrity XtractIM实战:5步搞定IC封装宽带模型提取(附BGA案例)

本文通过一个典型BGA封装案例,详细介绍了使用Cadence Sigrity XtractIM工具进行IC封装宽带模型提取的五步实战流程。内容涵盖从环境准备、参数设置、结果验证到模型导出的完整操作,重点阐述了如何利用XtractIM生成高精度、紧凑的宽带SPICE模型,以解决高速电路设计中因封装模型不准导致的信号与电源完整性问题,助力工程师提升仿真精度与设计效率。

a1b2c的博客 320

基于STM32的Modbus TCP多主站数据监测

Modbus TCP通信协议在STM32上实现,STM32作为服务器采集内部传感器数据,并通过ADC进行转换,存入寄存器。两个PC机作为客户端访问服务器,服务器通过Socket通信实现监听连接,将数据发送给客户端。

hyp12347的博客 4294

Java基础:一种实现数据库连接池的方法

 数据库连接池在编写应用服务是经常需要用到的模块,太过频繁的连接数据库对服务性能来讲是一个瓶颈,使用缓冲池技术可以来消除这个瓶颈。我们可以在互联网上找到很多关于数据库连接池的源程序,但是都发现这样一个共同的问题:这些连接池的实现方法都不同程度地增加了与使用者之间的耦合度。很多的连接池都要求用户通过其规定的方法获取数据库的连接,这一点我们可以理解,毕竟目前所有的应用服务器取数据库连接的方

走向架构师之路 749

基础的pdf病毒木马

基础的pdf病毒木马 环境: 攻击机:Kali 目标操作系统:Windows 10或Windows 7 (关闭防火墙和安全软件) 目标软件:Adobe Reader 8.1.2 msf框架搜索:adobe-pdf 1.打开msfconsole 2.搜索 adobe_pdf模块 3.加载攻击模块并设置payload 4.运行生成pdf 5.将pdf拖入到win10 6.打开msf,加...

小小猪的博客 4624

java项目开发实践经验之二:几种常见数据库连接池的使用比较

笔者曾经主持以及经历的几个产品及项目中,包括了各种数据库及应用服务器,基本上几种常见的数据库连接池都用到了,根据使用的情况把这些连接池比较一下吧。 感觉在介绍之前有必要阐述一下连接池的几个概念,有助于后边一些文字的理解。 最原始的数据库使用就是打开一个连接并进行使用,使用过后一定要关闭连接释放资源。由于频繁的打开和关闭连接对jvm包括数据库 都有一定的资源负荷,尤其应用压力较大时资源...

ZHBIT17612的专栏 913

【k8s故障处理篇】calico-kube-controllers状态为“ImagePullBackOff”解决办法

【k8s故障处理篇】calico-kube-controllers状态为“ImagePullBackOff”解决办法

jks212454的博客 2308

主题035:计算流体力学(CFD)

计算流体力学(Computational Fluid Dynamics, CFD)是利用数值方法求解流体流动、传热传质等问题的学科。CFD已成为化学反应工程中反应器设计和优化的重要工具。∂ρ∂t+∇⋅(ρu)=0 \frac{\partial \rho}{\partial t} + \nabla \cdot (\rho \mathbf{u}) = 0 ∂t∂ρ​+∇⋅(ρu)=0对于不可压缩流动:∇⋅u=0 \nabla \cdot \mathbf{u} = 0 ∇⋅u=0动量方程:∂(ρu)∂t+∇⋅(ρ

kkchenjj的博客 267

创新实训——服务端开发总结

       本来我是擅长安卓客户端开发的,对服务端开发只是略懂,对于SSH框架也只是大体了解,没有实际使用过。这次创新实训,因为必须搭建服务器,所以我不得不完成这个任务。         一开始的几天,我一直在忙着搭建环境,包括服务器的、本地的环境,而且必须要配置正确的参数,比如远程tomcat debug的配置、mysql编码格式的配置。         终于,环境搭建好后,我开始设计数据...

UnLongChemin的博客 355

机器人轨迹规划——三次样条轨迹1(基于速度的求解方法)

三次样条轨迹是利用三次样条曲线来对给定的一系列点进行插值,从而得到一个光滑的轨迹。三次样条因为每段的多项式次数最高都是三阶的,所以可以得到2阶导数连续,也就是加速度连续的轨迹。假设给定了一系列的点q0q1q2qnq0​q1​q2​...qn​,以及每个点对应的参数t0t1t2tnt0​t1​t2​...tn​,计算一条三次样条曲线sts(t)st,该曲线通过给定的点q0q1q2qnq0​q1。

出门搔白首,若负平生志 1471

JavaWeb(实训八)--11章 数据库连接池与DBUtils工具

为了更加简单地使用JDBC,Apache 组织提供了一个DBUtils 工具,它是操作数据库的一个组件,实现 了对JDBC的简单封装,可以在不影响数据库访问性能的情况下简化JDBC的编码工作量。DBUtils工具要有 三个作用。写数据。读数据优化性能。

2301_76890677的博客 1570

FPGA发展趋势:异构计算、AI加速、可重构计算

FPGA技术正朝着异构计算、AI加速和可重构计算三大方向发展。作为高效能计算平台,FPGA在异构架构中与CPU/GPU协同工作,发挥低延迟、高能效优势;在AI领域通过定制化架构实现边缘推理加速;其硬件可重构特性支持动态适应多样化计算需求。最新进展包括部分可重构技术、智能网卡和边缘AI应用。未来,FPGA将在自适应计算、量子接口和软件定义硬件等领域持续突破,成为异构计算架构的核心组件,推动硬件与软件的深度融合。性能对比显示FPGA在能效比(5-20TOPS/W)和灵活性方面具有显著优势。

2301_79143213的博客 969

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

创新实训1

项目实训1 1. 背景 建立数据库连接耗时耗费资源,一个数据库服务器能够同时建立的连接数也是有限的,在大型的Web应用中,可能同时会有成百上千的访问数据库的请求,如果Web应用程序为每一个客户请求分配一个数据库连接,将导致性能的急剧下降。 数据库连接池的意义在于,能够重复利用数据库连接(有点类似线程池的部分意义),提高对请求的响应时间和服务器的性能。 连接池中提前预先建立了多个数据库连接对象,然后将连接对象保存到连接池中,当客户请求到来时,直接从池中取出一个连接对象为客户服务,当请求完成之后,客户程序调用c

weixin_45774350的博客 211

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

【项目实训01】初始项目搭建

在本周的项目创新实训中,我们团队顺利开启了项目的初始搭建工作。接下来,将简要介绍我们项目的核心结构及所用技术栈。

Nix_zz的博客 852

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

[实训]SSH配置数据库连接池

在配置ssh的application.xml里直接加入一下xml代码块: <!-- 配置c3p0数据库连接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Dri

zhagzheguo的博客 3756

数据库实训全流程:从MySQL环境搭建到性能优化实战

数据库作为现代信息系统的核心组件,其核心功能是结构化数据的存储、管理和高效访问。其工作原理基于关系模型,通过SQL语言实现数据的定义、操作和控制。掌握数据库技术对于构建可靠、高性能的应用系统具有重要价值,广泛应用于电商、金融、社交等各类互联网业务场景。在实践层面,数据库实训是连接理论与工程的关键环节,涉及环境搭建、表结构设计、SQL优化等核心技能。本文聚焦mysql数据库实训,深入探讨如何通过docker容器化部署快速构建开发环境,并详解索引优化、事务控制等性能调优技巧,帮助读者构建完整的数据库实战能力闭环

weixin_30614109的博客 414

山东大学创新实训9——从 SQLite 到 PostgreSQL

迁移完成后,数据库锁定错误彻底消失,并发写入能力大幅提升。asyncpg 连接池的复用机制减少了连接建立开销,JSONB 类型对游戏属性等动态数据的存取更加高效。这次迁移验证了一个重要经验:数据库选型需要与业务并发模型匹配,SQLite 适合单机低并发场景,而需要处理并发写入的网络服务则应该从一开始就考虑使用 PostgreSQL 这样的专业数据库。

LQS0529的博客 353

创新实训——数据库连接池的实现(三)

   4.实现数据库连接管理的接口类 ConnectionManager负责提供获取连接的接口,使用单例模式。 public class ConnectionManager { private static ConnectionManager INSTANCE; private static ConnectionPool connectionPool; publi...

UnLongChemin的博客 210

2021-06-24Java实训学习笔记04---连接池

Java实训学习笔记04---一级目录二级目录三级目录 一级目录 二级目录 三级目录

椰博客 149

实训5 python连接mysql数据库

项目分值说明环境准备10分正确安装Python、MySQL、驱动数据库连接15分成功连接并输出提示数据增删改查40分每项操作完整、正确代码规范15分有注释、模块化、命名规范问题排查10分能正确处理异常与错误总分100分使用建立连接。使用执行SQL。使用提交事务。使用关闭连接。所有参数必须使用%s占位符,防止SQL注入。所有脚本运行成功,数据查询正确,无异常报错,即为实训完成!```pythontry:# 数据库连接参数。

qq_41839921的博客 503

数据库实战能力培养:从环境搭建到性能优化的全链路实训指南

数据库作为现代应用的核心数据存储与管理组件,其核心原理围绕数据的结构化存储、高效检索与事务一致性保障展开。理解其底层运行机制,如索引结构、锁与并发控制、查询优化器等,是构建高性能、高可靠系统的技术基石。在工程实践中,数据库连接池是提升应用性能的关键技术,通过复用连接减少开销;而数据迁移则是系统演进、架构升级中的常见场景,涉及异构数据源同步与一致性保障。本文聚焦数据库学习的实战化转型,通过模拟真实工作场景,深入探讨连接池配置优化与跨数据库数据迁移等核心实战技能,旨在帮助学习者构建从环境搭建、SQL编程到运维调

weixin_30896825的博客 373

创新实训——数据库连接池的实现(二)

3.使用代理模式实现RealConnection和RealPreparedStatement   1.RealConnection持有一个数据库连接Connection,并且管理连接的负载和空闲时间。 public class RealConnection implements IStatementCallback { private Connection connection; ...

UnLongChemin的博客 220
上一篇: 创新实训——使用Gson下发数据
下一篇: 创新实训——数据库连接池的实现(二)
VoyageLointain
博客等级 码龄10年 1粉丝 21原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值