Java数据库连接池--DBCP浅析.
一. 为何要使用数据库连接池
假设网站一天有很大的访问量,数据库服务器就需要为每次连接创建一次数据库连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、拓机。
数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现的尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标.数据库连接池正式针对这个问题提出来的.数据库连接池负责分配,管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。
数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中, 这些数据库连接的数量是由最小数据库连接数来设定的.无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量.连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中.
数据库连接池的最小连接数和最大连接数的设置要考虑到以下几个因素:
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 的例子, 然后根据例子来分析:
DBCPUtils:

- 1 public class DBCPUtils {
- 2 private static DataSource ds;//定义一个连接池对象
- 3 static{
- 4 try {
- 5 Properties pro = new Properties();
- 6 pro.load(DBCPUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties"));
- 7 ds = BasicDataSourceFactory.createDataSource(pro);//得到一个连接池对象
- 8 } catch (Exception e) {
- 9 throw new ExceptionInInitializerError("初始化连接错误,请检查配置文件!");
- 10 }
- 11 }
- 12 //从池中获取一个连接
- 13 public static Connection getConnection() throws SQLException{
- 14 return ds.getConnection();
- 15 }
- 16
- 17 public static void closeAll(ResultSet rs,Statement stmt,Connection conn){
- 18 if(rs!=null){
- 19 try {
- 20 rs.close();
- 21 } catch (SQLException e) {
- 22 e.printStackTrace();
- 23 }
- 24 }
- 25
- 26 if(stmt!=null){
- 27 try {
- 28 stmt.close();
- 29 } catch (SQLException e) {
- 30 e.printStackTrace();
- 31 }
- 32 }
- 33
- 34 if(conn!=null){
- 35 try {
- 36 conn.close();//关闭
- 37 } catch (SQLException e) {
- 38 e.printStackTrace();
- 39 }
- 40 }
- 41 }
- 42 }

在这个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();
- }
3.1 接下来看createDataSoruce() 方法:

- 1 protected synchronized DataSource createDataSource()
- 2 throws SQLException {
- 3 if (closed) {
- 4 throw new SQLException("Data source is closed");
- 5 }
- 6
- 7 // Return the pool if we have already created it
- 8 if (dataSource != null) {
- 9 return (dataSource);
- 10 }
- 11
- 12 // create factory which returns raw physical connections
- 13 ConnectionFactory driverConnectionFactory = createConnectionFactory();
- 14
- 15 // create a pool for our connections
- 16 createConnectionPool();
- 17
- 18 // Set up statement pool, if desired
- 19 GenericKeyedObjectPoolFactory statementPoolFactory = null;
- 20 if (isPoolPreparedStatements()) {
- 21 statementPoolFactory = new GenericKeyedObjectPoolFactory(null,
- 22 -1, // unlimited maxActive (per key)
- 23 GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL,
- 24 0, // maxWait
- 25 1, // maxIdle (per key)
- 26 maxOpenPreparedStatements);
- 27 }
- 28
- 29 // Set up the poolable connection factory
- 30 createPoolableConnectionFactory(driverConnectionFactory, statementPoolFactory, abandonedConfig);
- 31
- 32 // Create and return the pooling data source to manage the connections
- 33 createDataSourceInstance();
- 34
- 35 try {
- 36 for (int i = 0 ; i < initialSize ; i++) {
- 37 connectionPool.addObject();
- 38 }
- 39 } catch (Exception e) {
- 40 throw new SQLNestedException("Error preloading the connection pool", e);
- 41 }
- 42
- 43 return dataSource;
- 44 }

从源代码可以看出,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步,一个数据源就形成了,这里明确一点,一个数据源本质就是连接池+连接+管理策略。下面,将对每一步做详细的分析。
3.2 JDBC连接工厂driverConnectionFactory的创建过程

- 1 protected ConnectionFactory createConnectionFactory() throws SQLException {
- 2 // Load the JDBC driver class
- 3 Class driverFromCCL = null;
- 4 if (driverClassName != null) {
- 5 try {
- 6 try {
- 7 if (driverClassLoader == null) {
- 8 Class.forName(driverClassName);
- 9 } else {
- 10 Class.forName(driverClassName, true, driverClassLoader);
- 11 }
- 12 } catch (ClassNotFoundException cnfe) {
- 13 driverFromCCL = Thread.currentThread(
- 14 ).getContextClassLoader().loadClass(
- 15 driverClassName);
- 16 }
- 17 } catch (Throwable t) {
- 18 String message = "Cannot load JDBC driver class '" +
- 19 driverClassName + "'";
- 20 logWriter.println(message);
- 21 t.printStackTrace(logWriter);
- 22 throw new SQLNestedException(message, t);
- 23 }
- 24 }
- 25
- 26 // Create a JDBC driver instance
- 27 Driver driver = null;
- 28 try {
- 29 if (driverFromCCL == null) {
- 30 driver = DriverManager.getDriver(url);
- 31 } else {
- 32 // Usage of DriverManager is not possible, as it does not
- 33 // respect the ContextClassLoader
- 34 driver = (Driver) driverFromCCL.newInstance();
- 35 if (!driver.acceptsURL(url)) {
- 36 throw new SQLException("No suitable driver", "08001");
- 37 }
- 38 }
- 39 } catch (Throwable t) {
- 40 String message = "Cannot create JDBC driver of class '" +
- 41 (driverClassName != null ? driverClassName : "") +
- 42 "' for connect URL '" + url + "'";
- 43 logWriter.println(message);
- 44 t.printStackTrace(logWriter);
- 45 throw new SQLNestedException(message, t);
- 46 }
- 47
- 48 // Can't test without a validationQuery
- 49 if (validationQuery == null) {
- 50 setTestOnBorrow(false);
- 51 setTestOnReturn(false);
- 52 setTestWhileIdle(false);
- 53 }
- 54
- 55 // Set up the driver connection factory we will use
- 56 String user = username;
- 57 if (user != null) {
- 58 connectionProperties.put("user", user);
- 59 } else {
- 60 log("DBCP DataSource configured without a 'username'");
- 61 }
- 62
- 63 String pwd = password;
- 64 if (pwd != null) {
- 65 connectionProperties.put("password", pwd);
- 66 } else {
- 67 log("DBCP DataSource configured without a 'password'");
- 68 }
- 69
- 70 ConnectionFactory driverConnectionFactory = new DriverConnectionFactory(driver, url, connectionProperties);
- 71 return driverConnectionFactory;
- 72 }

上面一连串代码干了什么呢?其实就干了两件事:1、获取数据库驱动 2、使用驱动以及参数(url、username、password)构造一个工厂。一旦这个工厂构建完毕了,就可以来生成连接,而这个连接的生成其实是驱动加上配置来完成的.
3.3 创建连接池的过程

- 1 protected void createConnectionPool() {
- 2 // Create an object pool to contain our active connections
- 3 GenericObjectPool gop;
- 4 if ((abandonedConfig != null) && (abandonedConfig.getRemoveAbandoned())) {
- 5 gop = new AbandonedObjectPool(null,abandonedConfig);
- 6 }
- 7 else {
- 8 gop = new GenericObjectPool();
- 9 }
- 10 gop.setMaxActive(maxActive);
- 11 gop.setMaxIdle(maxIdle);
- 12 gop.setMinIdle(minIdle);
- 13 gop.setMaxWait(maxWait);
- 14 gop.setTestOnBorrow(testOnBorrow);
- 15 gop.setTestOnReturn(testOnReturn);
- 16 gop.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
- 17 gop.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
- 18 gop.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
- 19 gop.setTestWhileIdle(testWhileIdle);
- 20 connectionPool = gop;
- 21 }

在创建连接池的时候,用到了common-pool里的GenericObjectPool,对于JDBC连接的缓存以及管理其实是交给GenericObjectPool的,DBCP其实只是负责创建这样一种pool然后使用它而已。
3.4 创建statement缓存池
一般来说,statement并不是重量级的对象,创建过程消耗的资源并不像JDBC连接那样重,所以没必要做缓存池化,这里为了简便起见,对此不做分析。
3.5 创建PoolableConnectionFactory
这一步是一个承上启下的过程,承上在于利用上面两部创建的连接工厂和连接池,构建PoolableConnectionFactory,启下则在于为后面的向连接池里添加连接做准备。
下面先上一张静态的类关系图:

- 1 xprotected void createPoolableConnectionFactory(ConnectionFactory driverConnectionFactory,
- 2 KeyedObjectPoolFactory statementPoolFactory, AbandonedConfig configuration) throws SQLException {
- 3 PoolableConnectionFactory connectionFactory = null;
- 4 try {
- 5 connectionFactory =
- 6 new PoolableConnectionFactory(driverConnectionFactory,
- 7 connectionPool,
- 8 statementPoolFactory,
- 9 validationQuery,
- 10 validationQueryTimeout,
- 11 connectionInitSqls,
- 12 defaultReadOnly,
- 13 defaultAutoCommit,
- 14 defaultTransactionIsolation,
- 15 defaultCatalog,
- 16 configuration);
- 17 validateConnectionFactory(connectionFactory);
- 18 } catch (RuntimeException e) {
- 19 throw e;
- 20 } catch (Exception e) {
- 21 throw new SQLNestedException("Cannot create PoolableConnectionFactory (" + e.getMessage() + ")", e);
- 22 }
- 23 }

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

- 1 public PoolableConnectionFactory(
- 2 ConnectionFactory connFactory,
- 3 ObjectPool pool,
- 4 KeyedObjectPoolFactory stmtPoolFactory,
- 5 String validationQuery,
- 6 int validationQueryTimeout,
- 7 Collection connectionInitSqls,
- 8 Boolean defaultReadOnly,
- 9 boolean defaultAutoCommit,
- 10 int defaultTransactionIsolation,
- 11 String defaultCatalog,
- 12 AbandonedConfig config) {
- 13
- 14 _connFactory = connFactory;
- 15 _pool = pool;
- 16 _config = config;
- 17 _pool.setFactory(this);
- 18 _stmtPoolFactory = stmtPoolFactory;
- 19 _validationQuery = validationQuery;
- 20 _validationQueryTimeout = validationQueryTimeout;
- 21 _connectionInitSqls = connectionInitSqls;
- 22 _defaultReadOnly = defaultReadOnly;
- 23 _defaultAutoCommit = defaultAutoCommit;
- 24 _defaultTransactionIsolation = defaultTransactionIsolation;
- 25 _defaultCatalog = defaultCatalog;
- 26 }

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

- 1 protected static void validateConnectionFactory(PoolableConnectionFactory connectionFactory) throws Exception {
- 2 Connection conn = null;
- 3 try {
- 4 conn = (Connection) connectionFactory.makeObject();
- 5 connectionFactory.activateObject(conn);
- 6 connectionFactory.validateConnection(conn);
- 7 connectionFactory.passivateObject(conn);
- 8 }
- 9 finally {
- 10 connectionFactory.destroyObject(conn);
- 11 }
- 12 }

先是用makeObject方法来创建一个连接,然后做相关验证(就是用一些初始化sql来试着执行一下,看看能不能连接到数据库),然后销毁连接,这里并没有向连接池添加连接,真正的添加连接在后面,不过,我们可以先通过下面一张时序图来看看makeObject方法到底做了什么。
下面是一张整体流程的时序图:
从图中可以看出,makeObject方法的大致流程:从driverConnectionFactory那里拿到底层连接,初始化验证,然后创建PoolableConnection,在创建这个PoolableConnection的时候,将PoolableConnection与连接池关联了起来,真正做到了连接池和连接之间的一对多的关系,这也为改变PoolableConnection的close方法提供了方便。
下面是makeObject方法的源代码:

- 1 public Object makeObject() throws Exception {
- 2 Connection conn = _connFactory.createConnection();
- 3 if (conn == null) {
- 4 throw new IllegalStateException("Connection factory returned null from createConnection");
- 5 }
- 6 initializeConnection(conn); //初始化,这个过程可有可无
- 7 if(null != _stmtPoolFactory) {
- 8 KeyedObjectPool stmtpool = _stmtPoolFactory.createPool();
- 9 conn = new PoolingConnection(conn,stmtpool);
- 10 stmtpool.setFactory((PoolingConnection)conn);
- 11 }
- 12 //这里是关键
- 13 return new PoolableConnection(conn,_pool,_config);
- 14 }

其中PoolableConnection的构造函数如下:
- public PoolableConnection(Connection conn, ObjectPool pool, AbandonedConfig config) {
- super(conn, config);
- _pool = pool;
- }
内部关联了一个连接池,这个连接池的作用体现在PoolableConnection的close方法中:

- 1 public synchronized void close() throws SQLException {
- 2 if (_closed) {
- 3 // already closed
- 4 return;
- 5 }
- 6
- 7 boolean isUnderlyingConectionClosed;
- 8 try {
- 9 isUnderlyingConectionClosed = _conn.isClosed();
- 10 } catch (SQLException e) {
- 11 try {
- 12 _pool.invalidateObject(this); // XXX should be guarded to happen at most once
- 13 } catch(IllegalStateException ise) {
- 14 // pool is closed, so close the connection
- 15 passivate();
- 16 getInnermostDelegate().close();
- 17 } catch (Exception ie) {
- 18 // DO NOTHING the original exception will be rethrown
- 19 }
- 20 throw (SQLException) new SQLException("Cannot close connection (isClosed check failed)").initCause(e);
- 21 }
- 22
- 23 if (!isUnderlyingConectionClosed) {
- 24 // Normal close: underlying connection is still open, so we
- 25 // simply need to return this proxy to the pool
- 26 try {
- 27 _pool.returnObject(this); // XXX should be guarded to happen at most once
- 28 } catch(IllegalStateException e) {
- 29 // pool is closed, so close the connection
- 30 passivate();
- 31 getInnermostDelegate().close();
- 32 } catch(SQLException e) {
- 33 throw e;
- 34 } catch(RuntimeException e) {
- 35 throw e;
- 36 } catch(Exception e) {
- 37 throw (SQLException) new SQLException("Cannot close connection (return to pool failed)").initCause(e);
- 38 }
- 39 } else {
- 40 // Abnormal close: underlying connection closed unexpectedly, so we
- 41 // must destroy this proxy
- 42 try {
- 43 _pool.invalidateObject(this); // XXX should be guarded to happen at most once
- 44 } catch(IllegalStateException e) {
- 45 // pool is closed, so close the connection
- 46 passivate();
- 47 getInnermostDelegate().close();
- 48 } catch (Exception ie) {
- 49 // DO NOTHING, "Already closed" exception thrown below
- 50 }
- 51 throw new SQLException("Already closed.");
- 52 }
- 53 }

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

- 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,当然它是对底层连接进行了封装。第三个则是连接池和连接的关系,在此表现为一对多的互相引用。对数据源的构建则是对连接池,连接以及连接池与连接的关系的构建,掌握了这些点,就基本能掌握数据源的构建。
Java数据库连接池--DBCP浅析.的更多相关文章
- [数据库连接池] Java数据库连接池--DBCP浅析.
前言对于数据库连接池, 想必大家都已经不再陌生, 这里仅仅设计Java中的两个常用数据库连接池: DBCP和C3P0(后续会更新). 一. 为何要使用数据库连接池假设网站一天有很大的访问量,数据库服务 ...
- java数据库连接池dbcp的使用
近年来,随着Internet/Intranet建网技术的飞速发展和在世界范围内的迅速普及,计算机 应用程序已从传统的桌面应用转到Web应用.基于B/S(Browser/Server)架构的3层开发模式 ...
- Java数据库连接池比较(c3p0,dbcp,proxool和BoneCP)
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp21 Java框架数据库连接池比较(c3p0,dbcp和proxool,Bo ...
- java常用数据库连接池 (DBCP、c3p0、Druid) 配置说明
1. 引言 1.1 定义 数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标.数据库 ...
- java之数据库连接池-dbcp&c3p0&dbutils
介绍 因为数据库连接对象的创建比较消耗性能,所以可以在应用程序启动时就在内存中开辟一片空间(集合)存放多个数据库连接对象,后面需要连接时直接从该空间中取而不用新创建:使用完毕后归还连接(将连接重新放回 ...
- 主流Java数据库连接池分析(C3P0,DBCP,TomcatPool,BoneCP,Druid)
主流数据库连接池 常用的主流开源数据库连接池有C3P0.DBCP.Tomcat Jdbc Pool.BoneCP.Druid等 C3p0: 开源的JDBC连接池,实现了数据源和JNDI绑定,支持JDB ...
- 一个JAVA数据库连接池实现源码
原文链接:http://www.open-open.com/lib/view/open1410875608164.html // // 一个效果非常不错的JAVA数据库连接池. // from:htt ...
- Java数据库连接池的几种配置方法(以MySQL数据库为例)
Java数据库连接池的几种配置方法(以MySQL数据库为例) 一.Tomcat配置数据源: 前提:需要将连接MySQL数据库驱动jar包放进Tomcat安装目录中common文件夹下的lib目录中 1 ...
- 常用数据库连接池 (DBCP、c3p0、Druid) 配置说明
1. 引言 1.1 定义 数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标.数据库 ...
随机推荐
- jsp文件中文乱码解决
文件顶加上 <%@ page contentType="text/html;charset=UTF-8" language="java" %>即可
- spring boot -- 配置文件application.properties 换成 application.yml
1.前言 其实两种配置文件在spring boot 的作用一样,只是写法不同 ,yml 可以写的内容更少 ,以树结构 书写内容,看起来很清晰, 但是 如果 项目配置文件设置为 既有properties ...
- react子组件向父组件传值
子组件向父组件传值,注意父组件传递函数的时候必须绑定this到当前父组件(handleEmail={this.handleEmail.bind(this)}),不然会报错 /***实现在输入框输入邮箱 ...
- 拓展 Array 方法
为 Array 对象扩展了一个迭代器之后,就可以利用这个法代器进一步拓展 Array 的方法,使其能够完成更多的实用功能. Array.prototype.each = function( f ) { ...
- Ribbon原理与应用
一.定义 Ribbon是请求的负载均衡器,它为我们提供了几种负载均衡算法:轮询.随机等. 二.配置 spring: cloud: loadbalancer: retry: enabled: true ...
- Pop Sequeue
题目描述 Given a stack which can keep M numbers at most. Push N numbers in the order of 1,2,3...,N and p ...
- Cesium入门8 - Configuring the Scene - 配置视窗
Cesium入门8 - Configuring the Scene - 配置视窗 Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coini ...
- redis实现简易在线聊天室
redis_flask简易聊天室 项目构建 这时一个基于Redis数据库的简单小项目,使用redis缓存数据,并通过flask部署到浏览器,运行截图如下: 输入名字后,就可以登陆到聊天室,主要包括三个 ...
- qt 简单登录界面(一)
widget.h #ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include<QLineEdit> class ...
- 使用AJAX请求调用出现HTTPS协议错误问题
前言: 这又是一个可能是半路就卡机的项目,在调用ajax的时候遇到了下面的这个错. js中有个ajax请求http,url是:http//:.js就提示请求了一个不安全的脚本,在发送ajax请求时,就 ...