自定义一个简单的JDBC连接池实现方法

一、什么是JDBC连接池?

在传统的JDBC连接中,每次获得一个Connection连接都需要加载通过一些繁杂的代码去获取,例如以下代码:

public static Connection getConn(){
  Connection conn = null;
  String url = "jdbc:mysql://localhost:3306/test";
  String user = "root";
  String password = "root";
  try {
   Class.forName("com.mysql.jdbc.Driver");
   conn = DriverManager.getConnection(url, user, password);
  } catch (ClassNotFoundException e) {
   e.printStackTrace();
  } catch (SQLException e) {
   e.printStackTrace();
  }
  return conn;
 }

这样繁杂的操作只为了获取一次连接,当然,我们可以将其封装成一个工具类来访问(上图以封装好Connection的连接),但是每一次连接都需要取加载一次是不是很浪费性能,为了优化性能,那么就出现了连接池。

连接池在初始化的时候就创建了几个连接供我们使用,当我们需要连接时只需要从连接池中获取已存在的连接,当初始化的几个连接都没有时,会重新创建一个连接,使用完连接后不会去销毁连接,而是归还给连接池供后面需要连接的使用。(当然,连接池不仅仅只是这么简单,这里就只做这些介绍)

常用的连接池有DBCP、C3P0,现在最主流是好像是阿里的Druid连接池,还有tomcat的自带的JNDI连接池

二、自定义一个简单的连接池

对自定义连接池的分析:

1.2.因为是连接池 ,我们需要实现DataSource接口,并实现其中的方法,基于我们的情况,我们关于与getConnection()方法;

2.既然要存放几个连接对象,那么我们用一个集合来存放它,基于会经常操作增加和删除那么选用LinkedList;

3.连接的销毁并不是销毁连接,而是将连接归还给连接池

编码:

1.创建一个类MyDataSource 并实现DataSource接口

当此类加载时它就需要有一个容器来存放Connection,所以定义一个静态的属性:

private static List<Connection> connectionList = new LinkedList<>();

2.因为需要取获得数据库连接,所以我们封装一个获取数据库连接的方法

public Connection getOneConnection(){
  Connection conn = null;
  try{
   //此处通过外部的properties文件来获取的数据,这样更加灵活。
   InputStream in = MyDataSource.class.getClassLoader().
     getResourceAsStream("jdbc/jdbc.properties");
   Properties pro = new Properties();
   pro.load(in);
   driver = pro.getProperty("driver");
   url = pro.getProperty("url");
   username = pro.getProperty("user");
   password = pro.getProperty("password");
   Class.forName(driver);
   conn = DriverManager.getConnection(url,username,password);
  }catch (Exception e){
   e.getStackTrace();
  }
  return conn;
 }

注意的是我这里通过propertie文件的获取的数据,可根据实际情况来选择

3.初始化几个连接放入容器中。可以使用静态代码块来实现,但是如果没有使用此数据源那么就造成了资源的浪费,所以我考虑将初始化几个连接的实现放到他的构造方法中,即当需要此连接池的时候他才会随之创建几个连接。如下:

public MyDataSource() {
  for (int i = 0; i < 5; i++) {
   Connection conn = getOneConnection();//调用创建连接的方法
   connectionList.add(conn);
  }
 }

4.现在开始重写外部从此连接池中获取连接的方法getConnection()

@Override
 public Connection getConnection() throws SQLException {
  Connection conn = null;
  if(connectionList == null || connectionList.size() <= 0){
   Connection connection = getConnection();
   connectionList.add(connection);
  }
  conn = connectionList.remove(0);
  return conn;
 }

5.创建一个对象返回的方法,即将用完的连接放入归还到连接池中

public void backConnection(Connection conn){
  connectionList.add(conn);
 }

OK,这样就完成了一个简单的自定义连接池,测试代码如下:

public static void main( String[] args ) throws SQLException
 {
  MyDataSource dataSource = new MyDataSource();
  Connection conn = dataSource.getConnection();
  String sql = "select * from user where u_id = ?";
  PreparedStatement ps = null;
  ResultSet rs = null;
  try {
   ps = conn.prepareStatement(sql);
   ps.setInt(1, 1);
   rs = ps.executeQuery();
   while (rs.next()) {
    System.out.println("id="+rs.getInt(1));
    System.out.println("username="+rs.getString(2));
    System.out.println("password="+rs.getString(3));
   }
  } catch (SQLException e) {
   e.printStackTrace();
  } finally {
   dataSource.backConnection(conn);
  }
 }

因为忽略,我的代码中没有关闭其他两个对象。

现在有一个小问题就是,我们的关闭连接是通过连接池的方法来实现的,但是,如果用户调用Connection对象的close方法,那么连接时被销毁了,并没有返回给连接池,那么我们来优化它,让用户使用close()方法不会去销毁连接,而是去归还连接。

方案有很多中,这里采用装饰着模式的一种。

优化:

1.新建一个类MyConnection来实现Connection接口,其中他有属性类型为Connection conn和一个Liis<Connection>。

private Connection conn;
 private List<Connection> pool;

 public MyConnection(Connection conn, List<Connection> pool) {
  this.conn = conn;
  this.pool = pool;
 }

2.然后实现接口的close方法

 @Override
 public void close() throws SQLException {
  System.out.println("回收连接");
  pool.add(conn);
 }

3.然后实现他获取Statement的方法,如果不实现那么获取此Statement会出现空指针错误,我这里就只实现了PreparedStatement的获取方法

@Override
 public PreparedStatement prepareStatement(String sql) throws SQLException {
  System.out.println("获得Statement");
  return conn.prepareStatement(sql);
 }

4.然后删除掉MyDataSource类中归还连接的方法backConnection,并将构造方法和获取连接的方法做如下改造

public MyDataSource2() {
  for (int i = 0; i < 5; i++) {
   Connection conn = getOneConnection();
   MyConnection myConn = new MyConnection(conn, connectionList);
   connectionList.add(myConn);
  }
 }
@Override
 public Connection getConnection() throws SQLException {
  Connection conn = null;
  if(connectionList == null || connectionList.size() <= 0){
   Connection connection = getConnection();
   MyConnection myConn = new MyConnection(connection, connectionList);
   connectionList.add(myConn);
  }
  conn = connectionList.remove(0);
  return conn;
 }

好了,这样用户直接调用我们的Connection的close方法就不会去销毁连接了,会正确的归还给了连接池了,对测试代码稍做修改即可测试。

以上这篇自定义一个简单的JDBC连接池实现方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

您可能感兴趣的文章:

  • 使用Java编写控制JDBC连接、执行及关闭的工具类
  • 详解SpringBoot配置连接池
  • Spring 数据库连接池(JDBC)详解
(0)

相关推荐

  • 使用Java编写控制JDBC连接、执行及关闭的工具类

    简单的Java数据库连接和关闭工具类   写JDBC应用的人常常为关闭资源而头痛不已,这些代码枯燥无味,如何才能用简单的代码进行关闭呢,下面我写了一个方法,可以解除你的痛苦: /** * 关闭所有可关闭资源 * * @param objs 可关闭的资源对象有Connection.Statement.ResultSet,别的类型资源自动忽略 */ public static void closeAll(Object... objs) { for (Object obj : objs) { if (

  • Spring 数据库连接池(JDBC)详解

    数据库连接池 对一个简单的数据库应用,由于对数据库的访问不是很频繁,这时可以简单地在需要访问数据库时,就新创建一个连接,就完后就关闭它,这样做也不会带来什么性能上的开销.但是对于一个复杂的数据库应用,情况就完全不同而,频繁的建立.关闭连接,会极大地减低系统的性能,因为对于连接的使用成了系统性能的瓶颈. 通过建立一个数据库连接池以及一套连接使用管理策略,可以达到连接复用的效果,使得一个数据库连接可以得到安全.高效的复用,避免了数据库连接频繁建立.关闭的开销. 数据库连接池的基本原理是在内部对象池中

  • 详解SpringBoot配置连接池

    内置的连接池 目前spring Boot中默认支持的连接池有dbcp,dbcp2, tomcat, hikari三种连接池. 数据库连接可以使用DataSource池进行自动配置. 由于Tomcat数据源连接池的性能和并发,在tomcat可用时,我们总是优先使用它. 如果HikariCP可用,我们将使用它. 如果Commons DBCP可用,我们将使用它,但在生产环境不推荐使用它. 最后,如果Commons DBCP2可用,我们将使用它. 以上的几种连接池,可以通过在配置application文

  • 自定义一个简单的JDBC连接池实现方法

    一.什么是JDBC连接池? 在传统的JDBC连接中,每次获得一个Connection连接都需要加载通过一些繁杂的代码去获取,例如以下代码: public static Connection getConn(){ Connection conn = null; String url = "jdbc:mysql://localhost:3306/test"; String user = "root"; String password = "root"

  • Java中JDBC连接池的基本原理及实现方式

    目录 一. 应用程序直接建立数据库连接模型 二.使用数据库连接池优化模型 1.关于连接池中的连接数量的一些规定: 2.编写数据库连接池 创建数据库连接池: 进一步封装一些相关数据库的类的方法 三.两个开源的数据库连接池 1.dbcp连接 (1)导入相关jar包 (2)在项目根目录增加配置文件dbcp.properties (3)程序实现dbcp连接 2.c3p0连接池 (1)导入相关的jar包 (2)在项目根目录下增加配置文件 (3)编写类文件,创建连接池 3.dbcp和c3p0不同之处 一.

  • java实现手写一个简单版的线程池

    有些人可能对线程池比较陌生,并且更不熟悉线程池的工作原理.所以他们在使用线程的时候,多数情况下都是new Thread来实现多线程.但是,往往良好的多线程设计大多都是使用线程池来实现的. 为什么要使用线程 降低资源的消耗.降低线程创建和销毁的资源消耗.提高响应速度:线程的创建时间为T1,执行时间T2,销毁时间T3,免去T1和T3的时间提高线程的可管理性 下图所示为线程池的实现原理:调用方不断向线程池中提交任务:线程池中有一组线程,不断地从队列中取任务,这是一个典型的生产者-消费者模型. 要实现一

  • Node.js使用MySQL连接池的方法实例

    本文实例讲述了Node.js使用MySQL连接池的方法.分享给大家供大家参考,具体如下: Nodejs如何使用MySQL Nodejs要连接MySQL,可以使用Nodejs的MysQL驱动来实现.比如,我们这里使用"node-mysql"连接数据库.我们使用下面的方式来连接数据库: 首先,我们需要使用nodejs的包管理工具(npm)安装mysql的驱动.命令行如下: npm install musql 现在,要在js文件中使用mysql,添加下面的代码到你的文件中: var mysq

  • springboot配置mongodb连接池的方法步骤

    application.yml 配置 mongodb: address: localhost:27017 database: soms username: admin password: 123456 # 连接池配置 clientName: soms-task # 客户端的标识,用于定位请求来源等 connectionTimeoutMs: 10000 # TCP连接超时,毫秒 readTimeoutMs: 15000 # TCP读取超时,毫秒 poolMaxWaitTimeMs: 3000 #当

  • go语言操作redis连接池的方法

    本文实例讲述了go语言操作redis连接池的方法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: func newPool(server, password string) *redis.Pool {     return &redis.Pool{         MaxIdle: 3,         IdleTimeout: 240 * time.Second,         Dial: func () (redis.Conn, error) {             c

  • Python自定义一个类实现字典dict功能的方法

    如下所示: import collections class Mydict(collections.UserDict): def __missing__(self, key): if isinstance(key, str): raise KeyError(key) return self[str(key)] def __contains__(self, key): return str(key) in self.data def __setitem__(self, key, item): se

  • 一个简单的node.js界面实现方法

    最近要写一个工具界面整合项目的功能属性,方便其他部门的人进行编辑,有点类似后台.会有部分数据上的交互.于是学习了下node.js后端的知识. 源码如下: // filename:myServer.js // a simple http server var fs = require('fs'), url = require('url'), path = require('path'), http = require('http'); //从命令行参数获取root目录,默认是当前目录 var ro

  • 使用docker部署一个简单的c/c++程序的方法

    一.首先建立一个 hello-world.cpp 文件 程序代码如下: #include <iostream> using namespace std; int main () { cout << "hello-world" << endl; cout << "my first docker" << endl; return 0; } 例如我是在我的home路径下建立一个DockerFile/hello-w

  • 利用python list完成最简单的DB连接池方法

    先来看查看效果: 在代码连接数据库后,并且执行三条sql后,将mysql直接重启掉,故我们的连接池连接均是不ok的,所以,它会全部删除再抓新的连接下来,重启mysql命令: 关于python代码: ''' 遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书! ''' #!/usr/bin/env python3 # -*- coding: UTF-8 -*- import pymysql im

随机推荐