一,常规数据库连接
常规数据库连接一般由以下六个步骤构成:阅读本文,建议大家已经掌握了扎实的互联网架构技术,可参考:互联网架构技术清单
-
装载数据库驱动程序;
-
建立数据库连接;
-
创建数据库操作对象
-
访问数据库,执行sql语句;
-
处理返回结果集
-
断开数据库连接。
public class TestMysqlConn {
public static void main(String[] args) {
Connection con;
Statement stmt;
ResultSet rs;
try {
//1,装载数据库驱动程序
Class.forName("com.mysql.jdbc.Driver").newInstance();
//2,建立数据库连接
con = DriverManager.getConnection("jdbc:mysql://3xmq.com:3306/test","root","root");
//3,创建数据库操作对象
stmt = con.createStatement();
//4,执行sql语句
rs = stmt.executeQuery("select * from _test");
//5,处理返回结果集
while(rs.next()){
int num = rs.getInt("id");
String name = rs.getString("name");
String des = rs.getString("description");
System.out.println(num + " " + name + " " + des);
}
//6,断开数据库连接
stmt.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
System.out.println("连接失败");
}
}
}
二,常规数据库连接底层原理
数据库本身实际上就是一个Server端程序在跑,我们开发的程序连接数据库,相当于启动了一个Client端,连接到Server端,也就是C/S模式!那么数据库连接本质上是基于什么协议呢?以mysql连接为例,常见两种连接场景命令如下:
1,mysql -h localhost -uroot -p(本地模式)
2,mysql -h 127.0.0.1 -uroot -p(IP模式)
对场景一,使用tcpdump抓包如下:
可以看到并没有抓到网络请求数据,说明它走的是本地socket协议,unix domain socket。
对场景二,使用tcpdump进行抓包如下:
可以看到,mysql的连接过程,内部实际上是经过tcp/ip协议的,mysql上层基于tcp/ip协议封装了自己的一套消息协议!说白了,底层是基于tcp/ip socket 协议!
在mysql中使用命令:show status,可以看到mysql实际上会创建一个线程来处理客户端连接上来的连接!如下图:
Threads_connected连接数是1,mysql此时有一个连接!
Threads_created为3,说明曾经有3个connection连接过数据库!
Threads_cached为2,mysql内部的线程连接池,将空闲的连接不是立即销毁而是放到线程连接池中,如果新加进来连接不是立刻创建线程而是先从线程连接池中找到空闲的连接线程,然后分配,如果没有才创建新的线程。可见mysql内部已经为我们做优化了。
Threads_running为1,当前活跃线程数为1。
小提示:
1,Threads_catched值不是无限大的,一般为32左右。 mysql是可以调整单线程和多线程模式的,单线程只允许一个线程连接mysql,其他连接将会被拒绝。
2,数据库本地unix domain socket连接快于tcp/ip连接
三,常规数据库连接优化空间
以mysql为例,要做优化,首先要寻找数据库连接占用的资源有哪些?
1,mysql每个连接是会创建一个线程的,可以登录mysql输入show status查看Threads_connected和Threads_created的大小,那么我们每连接一次mysql就会创建一个线程,每次断开又会销毁一个线程。
数据库连接的创建和销毁本质就是线程的创建和销毁,而创建线程和销毁线程的资源消耗是非常大的。系统为每个线程分配栈空间,可以通过ulimis -s来查看,ubuntu 14.04默认是8M,那么100个连接就是800M,很吃内存的。其次mysql数据库会为每个连接分配连接缓冲区和结果缓冲区,也是要消耗时间的。
2,mysql的每次连接,都会进行tcp3次握手和断开时的4次挥手,分配一些缓存空间,也会消耗一定的时间。
如下图:
数据库连接池有效的避免了上述的问题,数据库连接池技术的思想非常简单,将数据库连接作为对象存储在一个Vector对象中,一旦数据库连接建立后,不同的数据库访问请求就可以共享这些连接,这样,通过复用这些已经建立的数据库连接,可以克服上述缺点,极大地节省系统资源和时间。
也就是我们提前创建好这些连接,然后需要用去取连接即可。和线程池的思想是一致的。
四,数据库连接池
数据库连接池(Connection pooling)是程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对池中的连接进行申请,使用,释放。创建数据库连接是一个很耗时的操作,也容易对数据库造成安全隐患。所以,在程序初始化的时候,集中创建多个数据库连接,并把他们集中管理,供程序使用,可以保证较快的数据库读写速度,还更加安全可靠。
连接池基本的思想是在系统初始化的时候,将数据库连接作为对象存储在内存中,当用户需要访问数据库时,并非建立一个新的连接,而是从连接池中取出一个已建立的空闲连接对象。使用完毕后,用户也并非将连接关闭,而是将连接放回连接池中,以供下一个请求访问使用。而连接的建立、断开都由连接池自身来管理。同时,还可以通过设置连接池的参数来控制连接池中的初始连接数、连接的上下限数以及每个连接的最大使用次数、最大空闲时间等等,也可以通过其自身的管理机制来监视数据库连接的数量、使用情况等。如下图:
数据库连接池机制:
(1)建立数据库连接池对象(服务器启动)。
(2)按照事先指定的参数创建初始数量的数据库连接(即:空闲连接数)。
(3)对于一个数据库访问请求,直接从连接池中得到一个连接。如果数据库连接池对象中没有空闲的连接,且连接数没有达到最大(即:最大活跃连接数),创建一个新的数据库连接。
(4)存取数据库。
(5)关闭数据库,释放所有数据库连接(此时的关闭数据库连接,并非真正关闭,而是将其放入空闲队列中。如实际空闲连接数大于初始空闲连接数则释放连接)。
(6)释放数据库连接池对象(服务器停止、维护期间,释放数据库连接池对象,并释放所有连接)。
数据库连接池在初始化时,按照连接池最小连接数,创建相应数量连接放入池中,无论是否被使用。当连接请求数大于最大连接数阀值时,会加入到等待队列!
数据库连接池的最小连接数和最大连接数的设置要考虑到以下几个因素:
-
最小连接数:是连接池一直保持的数据库连接,所以如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费.
-
最大连接数:是连接池能申请的最大连接数,如果数据库连接请求超过次数,后面的数据库连接请求将被加入到等待队列中,这会影响以后的数据库操作
-
如果最小连接数与最大连接数相差很大:那么最先连接请求将会获利,之后超过最小连接数量的连接请求等价于建立一个新的数据库连接.不过,这些大于最小连接数的数据库连接在使用完不会马上被释放,他将被放到连接池中等待重复使用或是空间超时后被释放.
五,常见数据库连接池
在Java中开源的常用的数据库连接池有以下几种 :
1)DBCP
DBCP是一个依赖Jakarta commons-pool对象池机制的数据库连接池.DBCP可以直接的在应用程序中使用,Tomcat的数据源使用的就是DBCP。
2)c3p0
c3p0是一个开放源代码的JDBC连接池,它在lib目录中与Hibernate一起发布,包括了实现jdbc3和jdbc2扩展规范说明的Connection 和Statement 池的DataSources 对象。
3)Druid
阿里出品,淘宝和支付宝专用数据库连接池,但它不仅仅是一个数据库连接池,它还包含一个ProxyDriver,一系列内置的JDBC组件库,一个SQL Parser。支持所有JDBC兼容的数据库,包括Oracle、MySql、Derby、Postgresql、SQL Server、H2等等。
Druid针对Oracle和MySql做了特别优化,比如Oracle的PS Cache内存占用优化,MySql的ping检测优化。
Druid提供了MySql、Oracle、Postgresql、SQL-92的SQL的完整支持,这是一个手写的高性能SQL Parser,支持Visitor模式,使得分析SQL的抽象语法树很方便。
简单SQL语句用时10微秒以内,复杂SQL用时30微秒。
通过Druid提供的SQL Parser可以在JDBC层拦截SQL做相应处理,比如说分库分表、审计等。Druid防御SQL注入攻击的WallFilter就是通过Druid的SQL Parser分析语义实现的。
六,数据库连接池配置
连接池配置大体可以分为基本配置、关键配置、性能配置等主要配置。
6.1 基本配置
基本配置是指连接池进行数据库连接的四个基本必需配置:
传递给JDBC驱动的用于连接数据库的用户名、密码、URL以及驱动类名。
DBCP |
c3p0 |
Druid |
|
用户名 |
username |
user |
username |
密码 |
password |
password |
password |
URL |
url |
jdbcUrl |
jdbcUrl |
驱动类名 |
driverClassName |
driverClass |
driverClassName |
注:在Druid连接池的配置中,driverClassName可配可不配,如果不配置会根据url自动识别dbType(数据库类型),然后选择相应的driverClassName。
6.2 关键配置
为了发挥数据库连接池的作用,在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数来设定的。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。
最小连接数:
是数据库一直保持的数据库连接数,所以如果应用程序对数据库连接的使用量不大,将有大量的数据库资源被浪费。
初始化连接数:
连接池启动时创建的初始化数据库连接数量。
最大连接数:
是连接池能申请的最大连接数,如果数据库连接请求超过此数,后面的数据库连接请求被加入到等待队列中。
最大等待时间:
当没有可用连接时,连接池等待连接被归还的最大时间,超过时间则抛出异常,可设置参数为0或者负数使得无限等待(根据不同连接池配置)。
DBCP |
c3p0 |
Druid |
|
最小连接数 |
minIdle(0) |
minPoolSize(3) |
minIdle(0) |
初始化连接数 |
initialSize(0) |
initialPoolSize(3) |
initialSize(0) |
最大连接数 |
maxTotal(8) |
maxPoolSize(15) |
maxActive(8) |
最大等待时间 |
maxWaitMillis(毫秒) |
maxIdleTime(0秒) |
maxWait(毫秒) |
注1:在DBCP连接池的配置中,还有一个maxIdle的属性,表示最大空闲连接数,超过的空闲连接将被释放,默认值为8。对应的该属性在Druid连接池已不再使用,配置了也没有效果,c3p0连接池则没有对应的属性。
注2:数据库连接池在初始化的时候会创建initialSize个连接,当有数据库操作时,会从池中取出一个连接。如果当前池中正在使用的连接数等于maxActive,则会等待一段时间,等待其他操作释放掉某一个连接,如果这个等待时间超过了maxWait,则会报错;如果当前正在使用的连接数没有达到maxActive,则判断当前是否空闲连接,如果有则直接使用空闲连接,如果没有则新建立一个连接。在连接使用完毕后,不是将其物理连接关闭,而是将其放入池中等待其他操作复用。
6.3 性能配置
预缓存设置:
即是PSCache,PSCache对支持游标的数据库性能提升巨大,比如说oracle。JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements属于单个connection而不是整个连接池,所以设置这个参数需要考虑到多方面的因素。
单个连接拥有的最大缓存数:要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100
连接有效性检测设置:
连接池内部有机制判断,如果当前的总的连接数少于miniIdle,则会建立新的空闲连接,以保证连接数得到miniIdle。如果当前连接池中某个连接在空闲了timeBetweenEvictionRunsMillis时间后任然没有使用,则被物理性的关闭掉。有些数据库连接的时候有超时限制(mysql连接在8小时后断开),或者由于网络中断等原因,连接池的连接会出现失效的情况,这时候设置一个testWhileIdle参数为true,可以保证连接池内部定时检测连接的可用性,不可用的连接会被抛弃或者重建,最大情况的保证从连接池中得到的Connection对象是可用的。当然,为了保证绝对的可用性,你也可以使用testOnBorrow为true(即在获取Connection对象时检测其可用性),不过这样会影响性能。
超时连接关闭设置:
removeAbandoned参数,用来检测到当前使用的连接是否发生了连接泄露,所以在代码内部就假定如果一个连接建立连接的时间很长,则将其认定为泄露,继而强制将其关闭掉。
作者微信:didumy,欢迎技术交流,来自:架构师小秘圈技术社区
相关推荐
本文将深入探讨如何使用ADO操作Oracle数据库,并介绍一个极简且包含连接池功能的ADO包装类——ado_conn 和 ado_pool。 首先,ADO为开发者提供了统一的接口来与多种数据库进行交互,包括Oracle。它包括了一系列的...
本文将深入探讨如何使用ADO操作Oracle数据库,并介绍一个极简且不涉及连接池的重封装类。 首先,ADO是微软提供的数据访问接口,它允许开发者通过OLE DB或ODBC进行数据库交互。在C++编程中,ADO库提供了COM接口,...
数据库连接池(c3p0):使用c3p0库来管理数据库连接。连接池可以提高数据库的性能和可扩展性,避免频繁创建和销毁连接。 数据库操作(dbutils):使用dbutils库来执行数据库操作,如查询、插入、更新和删除。...
HikariCP被誉为最快的Java连接池,它的设计目标是极简和高性能,具有良好的线程安全性和资源管理机制。C3P0则是一个开源的JDBC连接池,提供了连接测试、自动重连等功能。DBCP是Apache的早期连接池实现,虽然功能齐全...
本门课程为极简java系列课程的第五篇,详细介绍了JDBC访问数据库方面的知识,包括jdbc,连接池技术,spring jdbc框架的使用, 课程采用案例教学,通过丰富的案例从各个角度阐释知识点,深入浅出的讲解确保每个知识...
例如,使用`PreparedStatement`可以防止SQL注入攻击,而连接池(如C3P0、HikariCP)则能有效管理数据库连接,提高应用程序的效率。 在实际的企业开发中,通常会使用ORM(对象关系映射)框架,如Hibernate或MyBatis...
7. **连接池**:在企业级应用中,使用连接池(如C3P0、HikariCP、Apache DBCP等)管理数据库连接,提高性能并节省资源。连接池提供初始化、获取、释放连接的功能,保证多线程环境下数据库连接的高效使用。 8. **ORM...
**极简的JDBC Java Web实例** 在Java Web开发中,JDBC(Java Database Connectivity)是连接...通过实践,你可以进一步掌握JDBC的高级特性,如批处理、事务管理以及连接池的使用,从而提高应用程序的性能和稳定性。
这些操作通常会通过连接池管理数据库连接,以提高性能和资源利用率。在`config.js`中,你可能会看到数据库连接配置,如主机名、用户名、密码和数据库名。 除了核心功能,框架还封装了一些常用辅助函数。例如: 1. ...
-- 其他相关依赖,如数据库连接池、日志库等 --> ``` 接下来,我们创建Spring的配置文件,通常命名为`applicationContext.xml`。在这个文件中,我们可以定义Bean及其依赖关系。例如,如果我们有一个`UserService`...
1. **数据库连接管理**:ORM框架通常会提供数据库连接池,以管理和优化数据库连接的创建和释放,确保资源的有效利用。 2. **实体映射**:FluentAdo会有一个配置机制,允许开发者用代码定义对象和数据库表之间的映射...
2. **自动化资源池维护**:DdwDao自动管理数据库连接,包括打开、关闭连接以及连接池的维护,减轻了开发者的负担,同时也提高了应用性能和稳定性。 3. **配置化**:开发者可以通过配置文件来自定义连接池、主键...
7. **安全性与性能**:虽然这是一个简化版的论坛,但依然可以涉及基本的安全措施,如防止SQL注入,以及提高性能的方法,如使用连接池。 【标签】"servlet 论坛 javaEE"进一步明确了项目的主题和所涉及的技术栈。这...
接着,创建数据库连接配置,例如 `application.properties`: ```properties spring.datasource.url=jdbc:mysql://localhost:3306/testdb spring.datasource.username=root spring.datasource.password=root spring...
通过连接池管理数据库连接,执行SQL查询,如SELECT、INSERT、UPDATE和DELETE,以及处理结果集。了解SQL语言的基本语法和最佳实践对于有效利用MySQL至关重要。 学习Node.js、Express和MySQL的过程中,你可能需要掌握...
- 数据库优化:使用连接池管理数据库连接,提高性能。 - 异步编程:运用Promise或async/await处理异步操作,避免回调地狱。 3. **聊天室应用(chatrooms)** - `chatrooms`项目通常基于WebSocket技术,实现实时...
- 可能还包括其他依赖库:例如日志库、数据库连接池等,这些都是JFinal运行所必需的。 接下来,我们将按照以下步骤来搭建JFinal项目: 1. 创建一个新的Java项目:在IDE中新建一个Java项目,并设置好项目的目录结构...
最后,不要忘记在`app.js`关闭数据库连接,以防内存泄漏: ```javascript process.on('SIGINT', function() { connection.end(function(err) { if (err) throw err; console.log('MySQL connection closed'); ...
4. **编写数据库操作**:在 Express 路由中,使用 `dbConfig.js` 中的连接池进行数据查询、插入、更新和删除操作。例如,获取所有用户: ```javascript const express = require('express'); const db = require('....