服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|JavaScript|易语言|

服务器之家 - 编程语言 - JAVA教程 - 自定义一个简单的JDBC连接池实现方法

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

2021-03-08 12:05samluby JAVA教程

下面小编就为大家分享一篇自定义一个简单的JDBC连接池实现方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

一、什么是JDBC连接池

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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,所以定义一个静态的属性:

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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.初始化几个连接放入容器中。可以使用静态代码块来实现,但是如果没有使用此数据源那么就造成了资源的浪费,所以我考虑将初始化几个连接的实现放到他的构造方法中,即当需要此连接池的时候他才会随之创建几个连接。如下:

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

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

?
1
2
3
4
5
6
7
8
9
10
@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.创建一个对象返回的方法,即将用完的连接放入归还到连接池中

 

?
1
2
3
public void backConnection(Connection conn){
  connectionList.add(conn);
 }

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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>。

?
1
2
3
4
5
6
7
private Connection conn;
 private List<Connection> pool;
 
 public MyConnection(Connection conn, List<Connection> pool) {
  this.conn = conn;
  this.pool = pool;
 }

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

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

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

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

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

?
1
2
3
4
5
6
7
public MyDataSource2() {
  for (int i = 0; i < 5; i++) {
   Connection conn = getOneConnection();
   MyConnection myConn = new MyConnection(conn, connectionList);
   connectionList.add(myConn);
  }
 }
?
1
2
3
4
5
6
7
8
9
10
11
@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连接池实现方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持服务器之家。

原文链接:http://www.cnblogs.com/samluby/archive/2017/12/19/8068277.html

延伸 · 阅读

精彩推荐
  • JAVA教程Java进阶教程之String类

    Java进阶教程之String类

    这篇文章主要介绍了Java进阶教程之String类,String类对象是不可变对象(immutable object),String类是唯一一个不需要new关键字来创建对象的类,需要的朋友可以参考下...

    junjie5092019-11-27
  • JAVA教程深入理解Java注解的使用方法

    深入理解Java注解的使用方法

    这篇文章主要为大家详细介绍了Java注解的使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    天NULL3232020-12-03
  • JAVA教程Spring依赖注入的三种方式小结

    Spring依赖注入的三种方式小结

    本篇文章主要介绍了Spring依赖注入的三种方式小结,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    飞扬小初2372020-12-16
  • JAVA教程MyBatis中#号与美元符号的区别

    MyBatis中#号与美元符号的区别

    #{变量名}可以进行预编译、类型匹配等操作,#{变量名}会转化为jdbc的类型。很多朋友不清楚在mybatis中#号与美元符号的不同,接下来通过本文给大家介绍两...

    java19936663032020-07-26
  • JAVA教程Java8处理List的双层循环问题

    Java8处理List的双层循环问题

    这篇文章主要介绍了Java8处理List的双层循环问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧 ...

    航海到IT的转变,梦想一直5342020-08-19
  • JAVA教程Java8 Lambda表达式详解及实例

    Java8 Lambda表达式详解及实例

    这篇文章主要介绍了Java8 Lambda表达式详解的相关资料,需要的朋友可以参考下...

    lqh3282020-06-18
  • JAVA教程Java中的四种单例模式浅析

    Java中的四种单例模式浅析

    这篇文章主要给大家介绍了关于Java中四种单例模式的相关资料,其中包括饿汉式、懒汉式、懒汉式(双重锁)及内部类等四种,分别给出了详细的示例代码和...

    4902020-09-29
  • JAVA教程java计算两个日期之前的天数实例(排除节假日和周末)

    java计算两个日期之前的天数实例(排除节假日和周末)

    下面小编就为大家带来一篇java计算两个日期之前的天数实例(排除节假日和周末)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小...

    Java之家3582020-12-01