返回顶部
首页 > 资讯 > 精选 >JDBC数据库连接池 怎么实现
  • 253
分享到

JDBC数据库连接池 怎么实现

2023-06-02 16:06:42 253人浏览 泡泡鱼
摘要

本篇内容介绍了“JDBC数据库连接池 怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!什么情况下使用连接池?对于一个简单的数据库应用,

本篇内容介绍了“JDBC数据库连接池 怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

什么情况下使用连接池?

对于一个简单的数据库应用,由于对于数据库的访问不是很频繁。这时可以简单地在需要访问数据库时,就新创建一个连接,用完后就关闭它,这样做也不会带来什么明显的性能上的开销。但是对于一个复杂的数据库应用,情况就完全不同了。频繁的建立、关闭连接,会极大的减低系统的性能,因为对于连接的使用成了系统性能的瓶颈。

使用连接池的好处

  1. 连接复用。通过建立一个数据库连接池以及一套连接使用管理策略,使得一个数据库连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销。

  2. 对于共享资源,有一个很著名的设计模式:资源池。该模式正是为了解决资源频繁分配、释放所造成的问题的。把该模式应用到数据库连接管理领域,就是建立一个数据库连接池,提供一套高效的连接分配、使用策略,最终目标是实现连接的高效、安全的复用。

连接池的实现

数据库连接池的基本原理是在内部对象池中维护一定数量的数据库连接,并对外暴露数据库连接获取和返回方法。

外部使用者可通过 getConnection 方法获取连接,使用完毕后再通过 close 方法将连接返回,注意此时连接并没有关闭,而是由连接池管理器回收,并为下一次使用做好准备。

Java 中有一个 DataSource 接口, 数据库连接池就是 DataSource 的一个实现

下面我们自己实现一个数据库连接池:

首先实现 DataSource, 这里使用 BlockingQueue 作为池 (只保留了关键代码)

import javax.sql.DataSource;import java.io.PrintWriter;import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;import java.sql.SQLFeatureNotSupportedException;import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.BlockingQueue;import java.util.logging.Logger;public class MyDataSource implements DataSource {    static {        try {            Class.forName("com.mysql.jdbc.Driver");        } catch (Exception e) {            e.printStackTrace();        }    }    //这里有个坑    //Mysql用的是5.5的    //驱动用的是最新的    //连接的时候会报The server time zone value '�й���׼ʱ��'    // is unrecognized or represents more than one time zone    //解决方法:    //1.在连接串中加入?serverTimezone=UTC    //2.在mysql中设置时区,默认为SYSTEM    //set global time_zone='+8:00'    private String url = "jdbc:mysql://localhost:3306/test?serverTimezone=UTC";    private String user = "root";    private String passWord = "123456";    private BlockingQueue<Connection> pool = new ArrayBlockingQueue<>(3);    public MyDataSource() {        initPool();    }    private void initPool() {        try {            for (int i = 0; i < 3; i++) {                pool.add(new MyConnection(                        DriverManager.getConnection(url, user, password), this));            }        } catch (SQLException e) {            e.printStackTrace();        }    }        @Override    public synchronized Connection getConnection() throws SQLException {        try {            return pool.take();        } catch (InterruptedException e) {            e.printStackTrace();        }        throw new RuntimeException("get connection failed!");    }    public BlockingQueue<Connection> getPool() {        return pool;    }    public void setPool(BlockingQueue<Connection> pool) {        this.pool = pool;    }}

实现自己的连接, 对原生连接进行封装, 调用 close 方法的时候将连接放回到池中

import java.sql.*; import java.util.Map; import java.util.Properties; importjava.util.concurrent.Executor; public class MyConnection implements Connection { //包装的连接private Connection conn; private MyDataSource dataSource; public MyConnection(Connection conn, MyDataSource dataSource) { this.conn = conn; this.dataSource = dataSource; } @Overridepublic Statement createStatement() throws SQLException { return conn.createStatement(); }@Override public PreparedStatement prepareStatement(String sql) throws SQLException { returnconn.prepareStatement(sql); } @Override public boolean getAutoCommit() throws SQLException {return conn.getAutoCommit(); } @Override public void setAutoCommit(boolean autoCommit) throwsSQLException { conn.setAutoCommit(autoCommit); } @Override public void commit() throwsSQLException { conn.commit(); } @Override public void rollback() throws SQLException { conn.rollback(); } @Override public void close() throws SQLException { //解决重复关闭问题 if(!isClosed()) { dataSource.getPool().add(this); } } @Override public boolean isClosed()throws SQLException { return dataSource.getPool().contains(this); } }

main 方法

import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException;import java.sql.Statement; public class Main { public static void main(String[] args) { DataSource source = new MyDataSource(); try { Connection conn = source.getConnection(); Statement st = conn.createStatement(); st.execute("INSERT INTO USER (name,age) values('bob',12)"); conn.close(); } catch (SQLException e) { e.printStackTrace(); } } }

数据源连接池的原理及Tomcat中的应用

在Java web开发过程中,会广泛使用到数据源。
我们基本的使用方式,是通过spring使用类似如下的配置,来声明一个数据源:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">        <property name="driverClassName" value="${jdbc.driverClassName}" />        <property name="url" value="${jdbc.url}" />        <property name="username" value="${jdbc.username}" />        <property name="password" value="${jdbc.password}" />        <property name="maxActive" value="100" />        <property name="maxIdle" value="20" />        <property name="validationQuery" value="SELECT 1 from dual" />        <property name="testOnBorrow" value="true" />    </bean>

在之后应用里对于数据库的操作,都基于这个数据源,但这个数据源连接池的创建、销毁、管理,对于用户都是近乎透明的,甚至数据库连接的获取,我们都看不到Connection对象了。
这种方式是应用自身的数据库连接池,各个应用之间互相独立。

在类似于Tomcat这样的应用服务器内部,也有提供数据源的能力,这时的数据源,可以为多个应用提供服务。

这一点类似于以前写过关于Tomcat内部的Connector对于线程池的使用,可以各个Connector独立使用线程池,也可以共用配置的Executor。(Tomcat的Connector组件)

那么,在Tomcat中,怎么样配置和使用数据源呢?

  1. 先将对应要使用的数据库的驱动文件xx.jar放到TOMCAT_HOME/lib目录下。

  2. 编辑TOMCAT_HOME/conf/context.xml文件,增加类似于下面的内容:

<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"          maxTotal="100" maxIdle="30" maxWaitMillis="10000"          username="root" password="pwd" driverClassName="com.mysql.jdbc.Driver"          url="jdbc:mysql://localhost:3306/test"/>
  1. 需要提供数据源的应用内,使用JNDI的方式获取

Context initContext = new InitialContext();Context envContext  = (Context)initContext.lookup("java:/comp/env");DataSource ds = (DataSource)envContext.lookup("jdbc/TestDB");Connection conn = ds.getConnection();
  1. 愉快的开始使用数据库…

我们看,整个过程也并不比使用Spring等框架进行配置复杂,在应用内获取连接也很容易。多个应用都可以通过第3步的方式获取数据源,这使得同时提供多个应用共享数据源很容易。

这背后的是怎么实现的呢?

这个容器的连接池是怎么工作的呢,我们一起来看一看。

在根据context.xml中配置的Resouce初始化的时候,会调用具体DataSource对应的实现类,Tomcat内部默认使用的BasicDataSource,在类初始化的时候,会执行这样一行代码DriverManager.getDrivers(),其对应的内容如下,主要作用是使用 java.sql.DriverManager实现的Service Provider机制,所有jar文件包含META-INF/services/java.sql.Driver文件的,会被自动发现、加载和注册,不需要在需要获取连接的时候,再手动的加载和注册。

public static java.util.Enumeration<Driver> getDrivers() {        java.util.Vector<Driver> result = new java.util.Vector<>();        for(DriverInfo aDriver : reGISteredDrivers) {            if(isDriverAllowed(aDriver.driver, callerClass)) {                result.addElement(aDriver.driver);            } else {                println("    skipping: " + aDriver.getClass().getName());            }        }        return (result.elements());    }

之后DataSourceFactory会读取Resouce中指定的数据源的属性,创建数据源。

在我们的应用内getConnection的时候,使用ConnectionFactory创建Connection, 注意在创建Connection的时候,重点代码是这个样子:

public PooledObject<PoolableConnection> makeObject() throws Exception {        Connection conn = _connFactory.createConnection();        initializeConnection(conn);        PoolableConnection pc = new PoolableConnection(conn,_pool, connJmxName);        return new DefaultPooledObject<>(pc);

这里的_pool是GenericObjectPool,连接的获取是通过其进行的。

public Connection getConnection() throws SQLException {        C conn = _pool.borrowObject();}

在整个pool中包含几个队列,其中比较关键的一个定义如下:

private final LinkedBlockingDeque<PooledObject<T>> idleObjects;

我们再看连接的关闭,

public void close() throws SQLException {    if (getDelegateInternal() != null) {        super.close();        super.setDelegate(null);    }}

这里的关闭,并不会真的调用到Connection的close方法,我们通过上面的代码已经看到,Connection返回的时候,其实是Connection的Wrapper类。在close的时候,真实的会调用到下面的代码

// NORMal close: underlying connection is still open, so we           // simply need to return this proxy to the pool           try {               _pool.returnObject(this);           } catch(IllegalStateException e) {}

所谓的return,是把连接放回到上面我们提到的idleObjects队列中。整个连接是放在一个LIFO的队列中,所以如果没有关闭或者超过最大空闲连接,就会加到队列中。而允许外的连接才会真实的销毁destory

int maxIdleSave = getMaxIdle();        if (isClosed() || maxIdleSave > -1 && maxIdleSave <= idleObjects.size()) {            try {                destroy(p);            } catch (Exception e) {                swallowException(e);            }        } else {            if (getLifo()) {                idleObjects.addFirst(p); // 这里。            } else {                idleObjects.addLast(p);            }            if (isClosed()) {                // Pool closed while object was being added to idle objects.                // Make sure the returned object is destroyed rather than left                // in the idle object pool (which would effectively be a leak)                clear();            }        }

“JDBC数据库连接池 怎么实现”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: JDBC数据库连接池 怎么实现

本文链接: https://lsjlt.com/news/230633.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • JDBC数据库连接池 怎么实现
    本篇内容介绍了“JDBC数据库连接池 怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!什么情况下使用连接池对于一个简单的数据库应用,由...
    99+
    2023-06-02
  • jdbc连接池怎么实现数据库访问
    JDBC连接池是一种管理数据库连接的技术,它可以提供可用的数据库连接给应用程序使用,从而提高数据库访问的性能和效率。以下是实现JDB...
    99+
    2023-09-15
    jdbc 数据库
  • Jdbc 链接数据库(含连接池)
    package com.ygsoft.gris.mapp.materialmanage.impl.util;import java.math.BigDecimal;import java.sql.Calla...
    99+
    2024-04-02
  • JDBC | JDBC API详解及数据库连接池
    👑 博主简介:    🥇 Java领域新星创作者    🥇 阿里云开发者社区专家博主、星级博主、技术博主 🤝 交流社区:BoBooY(优质编程学习笔记社区) 前言:...
    99+
    2023-08-20
    java 数据库 mysql
  • JDBC02 利用JDBC连接数据库【使用数据库连接池】
    1 使用Statement执行含有动态信息的SQL语句时有几个不足:  1.1 由于需要将动态数据拼接到SQL语句中,这导致程序复杂度高,容易出错  1.2 拼接的数据若含有SQL语法内容就会导致拼接后的S...
    99+
    2024-04-02
  • C++怎么实现数据库连接池
    本文小编为大家详细介绍“C++怎么实现数据库连接池”,内容详细,步骤清晰,细节处理妥当,希望这篇“C++怎么实现数据库连接池”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。项目背景为了提高Mysql数据库的访问瓶颈...
    99+
    2023-07-05
  • 数据库连接池的原理?连接池使用什么数据结构实现?实现连接池?
    早期我们怎么进行数据库操作呢? 1、原理:一般来说,Java应用程序访问数据库的过程是: 加载数据库驱动程序; 通过jdbc建立数据库连接; 访问数据库,执行SQL语句; 断开数据库连接。 2、代码 1 //查询所有用户 ...
    99+
    2015-09-26
    数据库连接池的原理?连接池使用什么数据结构实现?实现连接池?
  • jdbc怎么连接数据库
    小编给大家分享一下jdbc怎么连接数据库,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!jdbc连接数据库的步骤:1、加载jdbc驱动程序;2、创建数据库的连接;3...
    99+
    2023-06-14
  • Python中怎么实现数据库连接池
    这篇文章将为大家详细讲解有关Python中怎么实现数据库连接池,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。示例:#-*-coding:utf-8-*-  import ...
    99+
    2023-06-17
  • Tomcat JDBC数据库连接池断开重连错误怎么办
    本文小编为大家详细介绍“Tomcat JDBC数据库连接池断开重连错误怎么办”,内容详细,步骤清晰,细节处理妥当,希望这篇“Tomcat JDBC数据库连接池断开重连错误怎么办”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习...
    99+
    2023-06-26
  • JDBC连接数据库实例
    package javacommon.base; import java.sql.Connection; import java.sql.PreparedStatement;...
    99+
    2024-04-02
  • jdbc怎么连接mysql数据库
    要连接MySQL数据库,需要以下步骤:1. 加载MySQL的JDBC驱动程序。可以从MySQL官方网站下载并安装MySQL Conn...
    99+
    2023-08-19
    jdbc mysql数据库
  • jdbc怎么连接sqlserver数据库
    1、下载并安装SQL Server JDBC驱动程序,可以从Microsoft官方网站上下载相应的驱动程序。 2、在Java项目中导...
    99+
    2024-04-09
    jdbc sqlserver
  • Java中怎么利用JDBC实现数据库连接
    Java中怎么利用JDBC实现数据库连接,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。 JDBC:...
    99+
    2024-04-02
  • JDBC连接数据库
    JDBC连接数据库主要有以下几个步骤:1、加载JDBC驱动程序Class.forName("com.mysql.jdbc.Driver");加载成功后,会将Driver类的实例注册到DriverManage...
    99+
    2024-04-02
  • JDBC 连接数据库
    一、通过Driver接口直接连接 public Connection getConnectionByDriver() throws Exception{  ...
    99+
    2024-04-02
  • DataSource与数据库连接池简介(JDBC简介)
    目录起源为何放弃DriverManager连接池数据源实现核心架构DataSourceAPI小结应用数据库连接池示例总结DataSource是作为DriverManager的替代品而...
    99+
    2022-11-13
    数据库连接池Data Source JDBC数据库连接池Data Source
  • java中jdbc怎么连接数据库
    在Java中使用JDBC连接数据库的步骤如下:1. 下载并安装数据库驱动程序:首先需要从数据库官方网站下载相应的JDBC驱动程序,并...
    99+
    2023-09-15
    java jdbc 数据库
  • JDBC怎么获取数据库连接
    这篇文章主要讲解了“JDBC怎么获取数据库连接”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“JDBC怎么获取数据库连接”吧!添加MySQL驱动:不同的数据库厂商都会有自己的实现java.sq...
    99+
    2023-06-29
  • jdbc怎么连接sql server数据库
    要连接 SQL Server 数据库,您需要执行以下步骤:1. 下载并安装 SQL Server JDBC 驱动程序。您可以从 Mi...
    99+
    2023-09-11
    jdbc sql server数据库
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作