Java数据库连接池之DBCP浅析_动力节点Java学院整理

一. 为何要使用数据库连接池

假设网站一天有很大的访问量,数据库服务器就需要为每次连接创建一次数据库连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、拓机。

数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现的尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标.数据库连接池正式针对这个问题提出来的.数据库连接池负责分配,管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。

数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中, 这些数据库连接的数量是由最小数据库连接数来设定的.无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量.连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中.

数据库连接池的最小连接数和最大连接数的设置要考虑到以下几个因素:

  1, 最小连接数:是连接池一直保持的数据库连接,所以如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费.
  2, 最大连接数:是连接池能申请的最大连接数,如果数据库连接请求超过次数,后面的数据库连接请求将被加入到等待队列中,这会影响以后的数据库操作
  3, 如果最小连接数与最大连接数相差很大:那么最先连接请求将会获利,之后超过最小连接数量的连接请求等价于建立一个新的数据库连接.不过,这些大于最小连接数的数据库连接在使用完不会马上被释放,他将被           放到连接池中等待重复使用或是空间超时后被释放.

二, 数据库连接池的原理及实现

到了这里我们已经知道数据库连接池是用来做什么的了, 下面我们就来说数据库连接池是如何来实现的.
1, 建立一个数据库连接池pool, 池中有若干个Connection 对象, 当用户发来请求需要进行数据库交互时则会使用池中第一个Connection对象.
2, 当本次连接结束时, 再将这个Connection对象归还池中, 这样就可以保证池中一直有足够的Connection对象.

public class SimplePoolDemo {
 //创建一个连接池
 private static LinkedList<Connection> pool = new LinkedList<Connection>(); 

 //初始化10个连接
 static{
  try {
   for (int i = 0; i < 10; i++) {
    Connection conn = DBUtils.getConnection();//得到一个连接
    pool.add(conn);
   }
  } catch (Exception e) {
   throw new ExceptionInInitializerError("数据库连接失败,请检查配置");
  }
 }
 //从池中获取一个连接
 public static Connection getConnectionFromPool(){
  return pool.removeFirst();//移除一个连接对象
 }
 //释放资源
 public static void release(Connection conn){
  pool.addLast(conn);
 }
}

以上的Demo就是一个简单的数据库连接池的例子, 先在静态代码块中初始化10个Connection对象, 当本次请求结束后再将Connection添加进池中.

这只是我们自己手动去实现的, 当然在实际生产中并不需要我们去手动去写数据库连接池. 下面就重点讲DBCP和C3P0的实现方式.

三, DBCP连接池

首先我们来看DBCP 的例子, 然后根据例子来分析:

#连接设置
 driverClassName=com.mysql.jdbc.Driver
 url=jdbc:mysql://localhost:3306/bjpowernode
 username=root
 password=abc

 #<!-- 初始化连接 -->
 initialSize=10

#最大连接数量
maxActive=50

#<!-- 最大空闲连接 -->
maxIdle=20

#<!-- 最小空闲连接 -->
minIdle=5

#<!-- 超时等待时间以毫秒为单位 60000毫秒/1000等于60秒 -->
maxWait=60000

#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=utf8

#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true

#driver default 指定由连接池所创建的连接的只读(read-only)状态。
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly=

#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=REPEATABLE_READ

DBCP配置文件
DBCPUtils:

public class DBCPUtils {
 private static DataSource ds;//定义一个连接池对象
 static{
  try {
   Properties pro = new Properties();
   pro.load(DBCPUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties"));
   ds = BasicDataSourceFactory.createDataSource(pro);//得到一个连接池对象
  } catch (Exception e) {
   throw new ExceptionInInitializerError("初始化连接错误,请检查配置文件!");
  }
 }
 //从池中获取一个连接
 public static Connection getConnection() throws SQLException{
  return ds.getConnection();
 }

 public static void closeAll(ResultSet rs,Statement stmt,Connection conn){
  if(rs!=null){
   try {
    rs.close();
   } catch (SQLException e) {
    e.printStackTrace();
   }
  }

  if(stmt!=null){
   try {
    stmt.close();
   } catch (SQLException e) {
    e.printStackTrace();
   }
  }

  if(conn!=null){
   try {
    conn.close();//关闭
   } catch (SQLException e) {
    e.printStackTrace();
   }
  }
 }
}

在这个closeAll方法中, conn.close(); 这个地方会将connection还回到池子中吗? DataSource 中是如何处理close()方法的呢?

上面的两个问题就让我们一起来看看源码是如何来实现的吧.

这里我们从ds.getConnection();入手, 看看一个数据源DataSource是如何创建connection的.
用eclipse导入:commons-dbcp-1.4-src.zip和commons-pool-1.5.6-src.zip则可查看源码:

BasicDataSource.class:(implements DataSource)

public Connection getConnection() throws SQLException {
  return createDataSource().getConnection();
}

接下来看createDataSoruce() 方法:

protected synchronized DataSource createDataSource()
 throws SQLException {
 if (closed) {
  throw new SQLException("Data source is closed");
 }

 // Return the pool if we have already created it
 if (dataSource != null) {
  return (dataSource);
 }

 // create factory which returns raw physical connections
 ConnectionFactory driverConnectionFactory = createConnectionFactory();

 // create a pool for our connections
 createConnectionPool();

 // Set up statement pool, if desired
 GenericKeyedObjectPoolFactory statementPoolFactory = null;
 if (isPoolPreparedStatements()) {
  statementPoolFactory = new GenericKeyedObjectPoolFactory(null,
     -1, // unlimited maxActive (per key)
     GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL,
     0, // maxWait
     1, // maxIdle (per key)
     maxOpenPreparedStatements);
 }

 // Set up the poolable connection factory
 createPoolableConnectionFactory(driverConnectionFactory, statementPoolFactory, abandonedConfig);

 // Create and return the pooling data source to manage the connections
 createDataSourceInstance();

 try {
  for (int i = 0 ; i < initialSize ; i++) {
   connectionPool.addObject();
  }
 } catch (Exception e) {
  throw new SQLNestedException("Error preloading the connection pool", e);
 }

 return dataSource;
}

从源代码可以看出,createDataSource()方法通过7步,逐步构造出一个数据源,下面是详细的步骤:

1、检查数据源是否关闭或者是否创建完成,如果关闭了就抛异常,如果已经创建完成就直接返回。

2、调用createConnectionFactory()创建JDBC连接工厂driverConnectionFactory,这个工厂使用数据库驱动来创建最底层的JDBC连接

3、调用createConnectionPool()创建数据源使用的连接池,连接池顾名思义就是缓存JDBC连接的地方。

4、如果需要就设置statement的缓存池,这个一般不需要设置

5、调用createPoolableConnectionFactory创建PoolableConnection的工厂,这个工厂使用上述driverConnectionFactory来创建底层JDBC连接,然后包装出一个PoolableConnection,这个PoolableConnection与连接池设置了一对多的关系,也就是说,连接池中存在多个PoolableConnection,每个PoolableConnection都关联同一个连接池,这样的好处是便于该表PoolableConnection的close方法的行为,具体会在后面详细分析。

6、调用createDataSourceInstance()创建内部数据源

7、为连接池中添加PoolableConnection

经过以上7步,一个数据源就形成了,这里明确一点,一个数据源本质就是连接池+连接+管理策略。下面,将对每一步做详细的分析。

JDBC连接工厂driverConnectionFactory的创建过程

protected ConnectionFactory createConnectionFactory() throws SQLException {
 // Load the JDBC driver class
 Class driverFromCCL = null;
 if (driverClassName != null) {
  try {
   try {
    if (driverClassLoader == null) {
     Class.forName(driverClassName);
    } else {
     Class.forName(driverClassName, true, driverClassLoader);
    }
   } catch (ClassNotFoundException cnfe) {
    driverFromCCL = Thread.currentThread(
      ).getContextClassLoader().loadClass(
        driverClassName);
   }
  } catch (Throwable t) {
   String message = "Cannot load JDBC driver class '" +
    driverClassName + "'";
   logWriter.println(message);
   t.printStackTrace(logWriter);
   throw new SQLNestedException(message, t);
  }
 }

 // Create a JDBC driver instance
 Driver driver = null;
 try {
  if (driverFromCCL == null) {
   driver = DriverManager.getDriver(url);
  } else {
   // Usage of DriverManager is not possible, as it does not
   // respect the ContextClassLoader
   driver = (Driver) driverFromCCL.newInstance();
   if (!driver.acceptsURL(url)) {
    throw new SQLException("No suitable driver", "08001");
   }
  }
 } catch (Throwable t) {
  String message = "Cannot create JDBC driver of class '" +
   (driverClassName != null ? driverClassName : "") +
   "' for connect URL '" + url + "'";
  logWriter.println(message);
  t.printStackTrace(logWriter);
  throw new SQLNestedException(message, t);
 }

 // Can't test without a validationQuery
 if (validationQuery == null) {
  setTestOnBorrow(false);
  setTestOnReturn(false);
  setTestWhileIdle(false);
 }

 // Set up the driver connection factory we will use
 String user = username;
 if (user != null) {
  connectionProperties.put("user", user);
 } else {
  log("DBCP DataSource configured without a 'username'");
 }

 String pwd = password;
 if (pwd != null) {
  connectionProperties.put("password", pwd);
 } else {
  log("DBCP DataSource configured without a 'password'");
 }

 ConnectionFactory driverConnectionFactory = new DriverConnectionFactory(driver, url, connectionProperties);
 return driverConnectionFactory;
}

上面一连串代码干了什么呢?其实就干了两件事:

1、获取数据库驱动

2、使用驱动以及参数(url、username、password)构造一个工厂。

一旦这个工厂构建完毕了,就可以来生成连接,而这个连接的生成其实是驱动加上配置来完成的.

创建连接池的过程

protected void createConnectionPool() {
  // Create an object pool to contain our active connections
  GenericObjectPool gop;
  if ((abandonedConfig != null) && (abandonedConfig.getRemoveAbandoned())) {
   gop = new AbandonedObjectPool(null,abandonedConfig);
  }
  else {
   gop = new GenericObjectPool();
  }
  gop.setMaxActive(maxActive);
  gop.setMaxIdle(maxIdle);
  gop.setMinIdle(minIdle);
  gop.setMaxWait(maxWait);
  gop.setTestOnBorrow(testOnBorrow);
  gop.setTestOnReturn(testOnReturn);
  gop.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
  gop.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
  gop.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
  gop.setTestWhileIdle(testWhileIdle);
  connectionPool = gop;
 }

在创建连接池的时候,用到了common-pool里的GenericObjectPool,对于JDBC连接的缓存以及管理其实是交给GenericObjectPool的,DBCP其实只是负责创建这样一种pool然后使用它而已。

 创建statement缓存池
一般来说,statement并不是重量级的对象,创建过程消耗的资源并不像JDBC连接那样重,所以没必要做缓存池化,这里为了简便起见,对此不做分析。

创建PoolableConnectionFactory

这一步是一个承上启下的过程,承上在于利用上面两部创建的连接工厂和连接池,构建PoolableConnectionFactory,启下则在于为后面的向连接池里添加连接做准备。

下面先上一张静态的类关系图:

protected void createPoolableConnectionFactory(ConnectionFactory driverConnectionFactory,
  KeyedObjectPoolFactory statementPoolFactory, AbandonedConfig configuration) throws SQLException {
 PoolableConnectionFactory connectionFactory = null;
 try {
  connectionFactory =
   new PoolableConnectionFactory(driverConnectionFactory,
           connectionPool,
           statementPoolFactory,
           validationQuery,
           validationQueryTimeout,
           connectionInitSqls,
           defaultReadOnly,
           defaultAutoCommit,
           defaultTransactionIsolation,
           defaultCatalog,
           configuration);
  validateConnectionFactory(connectionFactory);
 } catch (RuntimeException e) {
  throw e;
 } catch (Exception e) {
  throw new SQLNestedException("Cannot create PoolableConnectionFactory (" + e.getMessage() + ")", e);
 }
}

可以看见,在创建PoolableConnectionFactory的时候,需要用到前面创建的driverConnectionFactory以及连接池connectionPool,那么那个构造函数到底干了先什么呢?

public PoolableConnectionFactory(
 ConnectionFactory connFactory,
 ObjectPool pool,
 KeyedObjectPoolFactory stmtPoolFactory,
 String validationQuery,
 int validationQueryTimeout,
 Collection connectionInitSqls,
 Boolean defaultReadOnly,
 boolean defaultAutoCommit,
 int defaultTransactionIsolation,
 String defaultCatalog,
 AbandonedConfig config) {

 _connFactory = connFactory;
 _pool = pool;
 _config = config;
 _pool.setFactory(this);
 _stmtPoolFactory = stmtPoolFactory;
 _validationQuery = validationQuery;
 _validationQueryTimeout = validationQueryTimeout;
 _connectionInitSqls = connectionInitSqls;
 _defaultReadOnly = defaultReadOnly;
 _defaultAutoCommit = defaultAutoCommit;
 _defaultTransactionIsolation = defaultTransactionIsolation;
 _defaultCatalog = defaultCatalog;
}

它在内部保存了真正的JDBC 连接的工厂以及连接池,然后,通过一句_pool.setFactory(this); 将它自己设置给了连接池。这行代码十分重要,要理解这行代码,首先需要明白common-pool中的GenericObjectPool添加内部元素的一般方法,没错,那就是必须要传入一个工厂Factory。GenericObjectPool添加内部元素时会调用addObject()这个方法,内部其实是调用工厂的makeObejct()方法来创建元素,然后再加入到自己的池中。_pool.setFactory(this)这句代码其实起到了启下的作用,没有它,后面的为连接池添加连接也就不可能完成。

当创建完工厂后,会有个validateConnectionFactory(connectionFactory);这个方法的作用仅仅是用来验证数据库连接可使用,看代码:

protected static void validateConnectionFactory(PoolableConnectionFactory connectionFactory) throws Exception {
 Connection conn = null;
 try {
  conn = (Connection) connectionFactory.makeObject();
  connectionFactory.activateObject(conn);
  connectionFactory.validateConnection(conn);
  connectionFactory.passivateObject(conn);
 }
 finally {
  connectionFactory.destroyObject(conn);
 }
}

先是用makeObject方法来创建一个连接,然后做相关验证(就是用一些初始化sql来试着执行一下,看看能不能连接到数据库),然后销毁连接,这里并没有向连接池添加连接,真正的添加连接在后面,不过,我们可以先通过下面一张时序图来看看makeObject方法到底做了什么。

下面是一张整体流程的时序图:

从图中可以看出,makeObject方法的大致流程:从driverConnectionFactory那里拿到底层连接,初始化验证,然后创建PoolableConnection,在创建这个PoolableConnection的时候,将PoolableConnection与连接池关联了起来,真正做到了连接池和连接之间的一对多的关系,这也为改变PoolableConnection的close方法提供了方便。

下面是makeObject方法的源代码:

public Object makeObject() throws Exception {
 Connection conn = _connFactory.createConnection();
 if (conn == null) {
  throw new IllegalStateException("Connection factory returned null from createConnection");
 }
 initializeConnection(conn); //初始化,这个过程可有可无
 if(null != _stmtPoolFactory) {
  KeyedObjectPool stmtpool = _stmtPoolFactory.createPool();
  conn = new PoolingConnection(conn,stmtpool);
  stmtpool.setFactory((PoolingConnection)conn);
 }
 //这里是关键
 return new PoolableConnection(conn,_pool,_config);
}

其中PoolableConnection的构造函数如下:

public PoolableConnection(Connection conn, ObjectPool pool, AbandonedConfig config) {
 super(conn, config);
 _pool = pool;
}

内部关联了一个连接池,这个连接池的作用体现在PoolableConnection的close方法中:

public synchronized void close() throws SQLException {
 if (_closed) {
  // already closed
  return;
 }

 boolean isUnderlyingConectionClosed;
 try {
  isUnderlyingConectionClosed = _conn.isClosed();
 } catch (SQLException e) {
  try {
   _pool.invalidateObject(this); // XXX should be guarded to happen at most once
  } catch(IllegalStateException ise) {
   // pool is closed, so close the connection
   passivate();
   getInnermostDelegate().close();
  } catch (Exception ie) {
   // DO NOTHING the original exception will be rethrown
  }
  throw (SQLException) new SQLException("Cannot close connection (isClosed check failed)").initCause(e);
 }

 if (!isUnderlyingConectionClosed) {
  // Normal close: underlying connection is still open, so we
  // simply need to return this proxy to the pool
  try {
   _pool.returnObject(this); // XXX should be guarded to happen at most once
  } catch(IllegalStateException e) {
   // pool is closed, so close the connection
   passivate();
   getInnermostDelegate().close();
  } catch(SQLException e) {
   throw e;
  } catch(RuntimeException e) {
   throw e;
  } catch(Exception e) {
   throw (SQLException) new SQLException("Cannot close connection (return to pool failed)").initCause(e);
  }
 } else {
  // Abnormal close: underlying connection closed unexpectedly, so we
  // must destroy this proxy
  try {
   _pool.invalidateObject(this); // XXX should be guarded to happen at most once
  } catch(IllegalStateException e) {
   // pool is closed, so close the connection
   passivate();
   getInnermostDelegate().close();
  } catch (Exception ie) {
   // DO NOTHING, "Already closed" exception thrown below
  }
  throw new SQLException("Already closed.");
 }
}

一行_pool.returnObject(this)表明并非真的关闭了,而是返还给了连接池。

到这里, PoolableConnectionFactory创建好了,它使用driverConnectionFactory来创建底层连接,通过makeObject来创建PoolableConnection,这个PoolableConnection通过与connectionPool关联来达到改变close方法的作用,当PoolableConnectionFactory创建好的时候,它自己已经作为一个工厂类被设置到了connectionPool,后面connectionPool会使用这个工厂来生产PoolableConnection,而生成的所有的PoolableConnection都与connectionPool关联起来了,可以从connectionPool取出,也可以还给connectionPool。接下来,让我们来看一看到底怎么去初始化connectionPool。

 创建数据源并初始化连接池

createDataSourceInstance();

try {
 for (int i = 0 ; i < initialSize ; i++) {
  connectionPool.addObject();
 }
 } catch (Exception e) {
  throw new SQLNestedException("Error preloading the connection pool", e);
 }

我们先看 createDataSourceInstance();

protected void createDataSourceInstance() throws SQLException {
 PoolingDataSource pds = new PoolingDataSource(connectionPool);
 pds.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
 pds.setLogWriter(logWriter);
 dataSource = pds;
}

其实就是创建一个PoolingDataSource,作为底层真正的数据源,这个PoolingDataSource比较简单,这里不做详细介绍

接下来是一个for循环,通过调用connectionPool.addObject();来为连接池添加数据库连接,下面是一张时序图:

可以看出,在3.5中创建的PoolableConnectionFactory在这里起作用了,addObject依赖的正是makeObject,而makeObject在上面也介绍过了。

到此为止,数据源创建好了,连接池里也有了可以使用的连接,而且每个连接和连接池都做了关联,改变了close的行为。这个时候BasicDataSource正是可以工作了,调用getConnection的时候,实际是调用底层数据源的getConnection,而底层数据源其实就是从连接池中获取的连接。

四.总结

整个数据源最核心的其实就三个东西:

一个是连接池,在这里体现为common-pool中的GenericObjectPool,它负责缓存和管理连接,所有的配置策略都是由它管理。

第二个是连接,这里的连接就是PoolableConnection,当然它是对底层连接进行了封装。

第三个则是连接池和连接的关系,在此表现为一对多的互相引用。对数据源的构建则是对连接池,连接以及连接池与连接的关系的构建,掌握了这些点,就基本能掌握数据源的构建。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • java实现mongodb的数据库连接池

    MongoDB是介于关系数据库和非关系数据库之间的一种产品,文件的存储格式为BSON(一种JSON的扩展),这里就主要介绍Java通过使用mongo-2.7.3.jar包实现mongodb连接池,具体的java代码实现如下: 数据库连接池配置参数: /** *@Description: mongo连接池配置文件 */ package cn.lulei.mongo.pool; public class MongoConfig { private static String userName;//用

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

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

  • Java数据库连接池之c3p0简介_动力节点Java学院整理

    c3p0是什么 c3p0的出现,是为了大大提高应用程序和数据库之间访问效率的. 它的特性: 编码的简单易用 连接的复用 连接的管理 说到c3p0,不得不说一下jdbc本身,c3p0愿意就是对数据库连接的管理,那么原有的概念还是得清晰:DriverManager.Connection.StateMent.ResultMent. jdbc:java database connective这套API,不用多说,是一套用于连接各式dbms或连接桥接器的api,两个层级:上层供应用方调用api,下层,定义

  • Java数据库连接池之proxool_动力节点Java学院整理

    Proxool是一种Java数据库连接池技术.sourceforge下的一个开源项目,这个项目提供一个健壮.易用的连接池,最为关键的是这个连接池提供监控的功能,方便易用,便于发现连接泄漏的情况. 目前是和DBCP以及C3P0一起,最为常见的三种JDBC连接池技术. 日前,Hibernate官方宣布由于Bug太多不再支持DBCP,而推荐使用 Proxool或C3P0. 下面通过一个Demo说明一下如何使用: 项目结构如下: DBLink.Java文件中的代码: package com.bjpowe

  • Spring Boot集成Druid数据库连接池

    1. 前言 Druid数据库连接池由阿里巴巴开源,号称是java语言中最好的数据库连接池,是为监控而生的.Druid的官方地址是:https://github.com/alibaba/druid 通过本文,我们可以看到 Spring Boot 如何配置数据源 Spring Boot 如何集成Druid数据库连接池 如何打开并访问Druid数据库连接池的监控功能 Spring Boot 使用JdbcTemplate操作数据库 2. 配置pom.xml <parent> <groupId&g

  • Java中常用的数据库连接池_动力节点Java学院整理

    定义 数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标.数据库连接池正是针对这个问题提出来的. 数据库连接池负责分配.管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个:释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏.这项技术能明显提高对数据库操作的性能. 参考资料 DBCP 下载地址:http://

  • C3P0连接池+MySQL的配置及wait_timeout问题的解决方法

     一.配置环境 spring4.2.4+mybatis3.2.8+c3p0-0.9.1.2+Mysql5.6.24 二.c3p0的配置详解及spring+c3p0配置 1.配置详解 官方文档 : http://www.mchange.com/projects/c3p0/index.html <c3p0-config> < default-config> <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数.Default: 3 --> <property

  • 数据库连接池c3p0配置_动力节点Java学院整理

    c3p0的配置方式分为三种,分别是 1.setters一个个地设置各个配置项 2.类路径下提供一个c3p0.properties文件 3.类路径下提供一个c3p0-config.xml文件 1.setters一个个地设置各个配置项 这种方式最繁琐,形式一般是这样: Properties props = new Properties(); InputStream in = ConnectionManager.class.getResourceAsStream("/c3p0.properties&q

  • Java实现数据库连接池简易教程

    一.引言 池化技术在Java中应用的很广泛,简而论之,使用对象池存储某个实例数受限制的实例,开发者从对象池中获取实例,使用完之后再换回对象池,从而在一定程度上减少了系统频繁创建对象销毁对象的开销.Java线程池和数据库连接池就是典型的应用,但并非所有的对象都适合拿来池化,对于创建开销比较小的对象拿来池化反而会影响性能,因为维护对象池也需要一定的资源开销,对于创建开销较大,又频繁创建使用的对象,采用池化技术会极大提高性能. 业界有很多成熟的数据库连接池,比如C3P0,DBCP,Proxool以及阿

  • Java实现数据库连接池的方法

    本文实例讲述了Java实现数据库连接池的方法.分享给大家供大家参考.具体如下: package com.kyo.connection; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.Driver; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; import j

随机推荐