01_数据库连接池,数据源,ResultSetMetaData,jdbc优化



一、数据库连接池

1.
什么是连接池

传统的开发模式下,Servlet处理用户的请求,找Dao查询数据,dao会创建与数据库之间的连接,完成数据查询后会关闭数据库的链接。

这样的方式会导致用户每次请求都要向数据库建立链接而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、宕机。

解决方案就是数据库连接池

连接池就是数据库连接对象的一个缓冲池

我们可以先创建10个数据库连接缓存在连接池中,当用户有请求过来的时候,dao不必创建数据库连接,而是从数据库连接池中获取一个,用完了也不必关闭连接,而是将连接换回池子当中,继续缓存

使用数据库连接池可以极大地提高系统的性能

2.
实现数据库连接池

jdbc统一了数据库的操作 
定义了规范

jdbc针对数据库连接池也定义的接口java.sql.DataSource,所有的数据库连接池实现都要实现该接口

该接口中定义了两个重载的方法

Connection getConnection()

Connection getConnection(String username,String password)

数据库连接池实现思路

1)定义一个类实现java.sql.DataSource接口

2)定义一个集合用于保存Connection对象,由于频繁地增删操作,用LinkedList比较好

3)实现getConnection方法,在方法中取出LinkedList集合中的一个连接对象返回

注意:

返回的Connection对象不是从集合中获得,而是删除

用户用完Connection,会调用close方法释放资源,此时要保证连接换回连接池,而不是关闭连接

重写close方法是难点,解决方案:装饰设计模式、动态代理

二、
数据源

通常我们把DataSource的实现,按其英文含义称之为数据源,数据源中都包含了数据库连接池的实现。

一些开源组织提供了数据源的独立实现,常用的有:

DBCP
数据库连接池

C3P0
数据库连接池

1. 
DBCP
数据源

介绍

DBCP
是 Apache
软件基金组织下的开源连接池实现

tomcat服务器就是使用DBCP作为数据库连接池

使用DBCP数据源,需要导入两个jar包

Commons-dbcp.jar:连接池的实现

Commons-pool.jar:连接池实现的依赖库

DBCP核心 API

BasicDataSource

数据源实现

BasicDataSourceFactory

用于创建数据源的工厂类

dbcp
创建连接池

方法1: 直接创建对象,设置参数

BasicDataSource bds = new BasicDataSource();

//
设置连接数据库需要的配置信息

bds.setDriverClassName("com.mysql.jdbc.Driver");

bds.setUrl("jdbc:mysql://localhost:3306/jdbc3");

bds.setUsername("root");

bds.setPassword("root");

//
设置连接池的参数

bds.setInitialSize(5);

bds.setMaxActive(10);

ds = bds

方法2:
通过工厂类创建对象,读取配置文件

try {

Properties prop =new Properties();

// 读配置文件

InputStream in =

JdbcUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");

prop.load(in);

ds =BasicDataSourceFactory.createDataSource(prop);

}catch (Exception e) {

throw newExceptionInInitializerError(e);

}

配置文件为dbcpconfig.properties

#连接设置

driverClassName=com.mysql.jdbc.Driver

url=jdbc:mysql://localhost:3306/jdbc3

username=root

password=root

#<!--
初始化连接 -->

initialSize=5

#最大连接数量

maxActive=10

#<!--
最大空闲连接 -->

maxIdle=10

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

maxWait=60000

#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]

#注意:"user"
与"password"
两个属性会被明确地传递,因此这里不需要包含他们。

connectionProperties=useUnicode=true;characterEncoding=gbk

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

defaultAutoCommit=true

#driver default
指定由连接池所创建的连接的只读(read-only)状态。

#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)

defaultReadOnly=

#driver default
指定由连接池所创建的连接的事务级别(TransactionIsolation)。

#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED,
READ_COMMITTED,REPEATABLE_READ, SERIALIZABLE

defaultTransactionIsolation=READ_UNCOMMITTED

2. 
C3P0
数据源

介绍

c3p0是一个开源的jdbc连接池,我们熟悉的Hibernate和
Spring 框架使用的都是该数据源

创建连接池对象

方法1:直接创建对象,设置参数

ComboPooledDataSource cpds = new ComboPooledDataSource();

cpds.setDriverClass("com.mysql.jdbc.Driver");

cpds.setJdbcUrl("jdbc:mysql://localhost:3306/jdbc3");

cpds.setUser("root");

cpds.setPassword("root");

cpds.setInitialPoolSize(5);

cpds.setMaxPoolSize(15);

方法2:读取配置文件

ComboPooledDataSource cpds = newComboPooledDataSource("itcast");

配置文件为c3p0-config.xml
该文件需要放在类路径下

<c3p0-config>

<default-config>

<!—- 默认配置
–->

<propertyname="initialPoolSize">5</property>

<propertyname="maxPoolSize">15</property>

<propertyname="driverClass">com.mysql.jdbc.Driver</property>

<propertyname="jdbcUrl">jdbc:mysql://localhost:3306/jdbc3</property>

<propertyname="user">root</property>

<propertyname="password">root</property>

</default-config>

<named-configname="xwh">

<propertyname="initialPoolSize">5</property>

<propertyname="maxPoolSize">15</property>

<propertyname="driverClass">com.mysql.jdbc.Driver</property>

<propertyname="jdbcUrl">jdbc:mysql://localhost:3306/jdbc3</property>

<propertyname="user">root</property>

<propertyname="password">root</property>

</named-config>

</c3p0-config>

三、ResultSetMetaData对象

元数据,可以理解为描述数据的数据

jdbc中的元数据是指数据库、表、列的定义信息

ResultSetMetaData对象表示结果集 ResultSet对象的元数据

获得该对象:

ResultSetMetaDatametaData = rs.getMetaData();

常用方法:

getColumnCount()
 返回resultset对象的列数

getColumnName(int column)
 获得指定列的名称

getColumnTypeName(int column)
获得指定列的类型

四、jdbc优化

使用jdbc对数据库进行crud操作时,会有很多重复的代码,仔细分析不难发现其实变化的只是其中几行代码

对于 cud(增删改)
操作,代码几乎完全一样,
唯一的区别就是sql语句不同,我们完全可以把相同的代码抽取出来定义在一个工具方法中,然后定义一个参数来接收sql语句

对于 r(查询)
操作,除SQL语句不同之外,根据操作的实体不同,对ResultSet结果集的处理也有所不相同,因此可义一个query方法,除以参数形式接收变化的SQL语句外,可以使用策略模式由qurey方法的调用者决定如何把ResultSet中的数据映射到实体对象中

优化后的工具类 JdbcUtils

//
通用的增删改方法

public
static
int update(String sql, Object[] params)
throws SQLException {

Connection conn =null;

PreparedStatementpstmt = null;

ResultSet rs = null;

try {

//
获得连接

conn =getConnection();

//
预编译sql

pstmt =conn.prepareStatement(sql);

//
将参数设置进去

for(int
i=0; params!=null&&i<params.length; i++) {

pstmt.setObject(i+1,params[i]);

}

//
发送sql

int num = pstmt.executeUpdate();

return num;

} finally {

//
释放资源

release(conn,pstmt, rs);

}

}

//
优化查询

public
static Object query(String sql, Object[] params,ResultSetHandler rsh)
throws SQLException {

Connection conn =null;

PreparedStatementpstmt = null;

ResultSet rs = null;

try {

//
获得连接

conn =getConnection();

//
预编译sql

pstmt =conn.prepareStatement(sql);

//
将参数设置进去

for(int
i=0; params!=null&&i<params.length;i++) {

pstmt.setObject(i+1,params[i]);

}

//
发送sql

rs =pstmt.executeQuery();

//
不知道别人想如何处理结果集

//
干脆想别人所要一个结果集的处理器

//
为了让当前代码继续,定义一个结果集处理器接口

//
策略模式,
规定算法,具体的算法留给将来的调用者实现

Object obj =rsh.handle(rs);

return obj;

} finally {

//
释放资源

release(conn,pstmt, rs);

}

}

结果集处理器接口

public interface ResultSetHandler {

// 处理结果集的方法

public Objecthandle(ResultSet rs);

}

实现类:

BeanListHandler

public class BeanListHandler implements ResultSetHandler{

private Classclazz;

publicBeanListHandler(Class clazz) {

this.clazz =clazz;

}

public Objecthandle(ResultSet rs) {

try {

// 取出结果集所有的记录,封装到bean,存入list返回

List list =new ArrayList();

while(rs.next()) {

Objectbean = clazz.newInstance();

// 获得元数据

ResultSetMetaDatametaData = rs.getMetaData();

// 获得列的数量

intcount = metaData.getColumnCount();

// 遍历列

for(inti=1; i<=count; i++) {

// 取列名

StringcolumnName = metaData.getColumnName(i);

// 取这列的值

Objectvalue = rs.getObject(columnName);

// 反射出属性

Fieldfield = clazz.getDeclaredField(columnName);

// 设置属性

field.setAccessible(true);

field.set(bean,value);

}

// 加入list

list.add(bean);

}

returnlist;

} catch(Exception e) {

throw newRuntimeException(e);

}

}

}

BeanHandler

public class BeanHandler implements ResultSetHandler {

private Classclazz;

publicBeanHandler(Class clazz) {

this.clazz =clazz;

}

public Objecthandle(ResultSet rs) {

// 不知道有几列数据,不知道列名,不知道封装到什么样的bean

// 表的列明和javabean的字段名一致

try {

if(rs.next()){

// 创建bean

Objectbean = clazz.newInstance();

// 封装数据

// 获得结果集的元数据

ResultSetMetaDatametaData = rs.getMetaData();

intcount = metaData.getColumnCount();

// 迭代取每一列的数据

for(inti=1; i<=count; i++) {

// 获得列名 
username

StringcolumnName = metaData.getColumnName(i);

// 获得数据ddd

Objectvalue = rs.getObject(columnName);

// 根据列名反射出映射的属性 username

Fieldfield = clazz.getDeclaredField(columnName);

// 为属性赋值

field.setAccessible(true);

field.set(bean,value);

}

returnbean;

}

return null;

} catch(Exception e) {

throw newRuntimeException(e);

}

}

}

ArrayHandler

//
取出第一行的所有记录存入一个Object数组

public class ArrayHandler implements ResultSetHandler {

public Objecthandle(ResultSet rs) {

try {

if(rs.next()) {

// 指向了第一行的记录

// 获得元数据

ResultSetMetaDatametaData = rs.getMetaData();

// 获得列数

intcount = metaData.getColumnCount();

// 创建数组

Object[]arr = new Object[count];

// 迭代所有列的值,存入数组

for(inti=1; i<=count; i++) {

Objectvalue = rs.getObject(i); // 获得指定列的值

arr[i-1]= value;

}

returnarr;

}

return null;

} catch(Exception e) {

throw newRuntimeException(e);

}

}

}

批处理

处理大数据

Clob Character large Object

text

Blob binary large object

时间: 2024-10-08 16:04:09

01_数据库连接池,数据源,ResultSetMetaData,jdbc优化的相关文章

JDBC整合c3p0数据库连接池 解决Too many connections错误

前段时间,接手一个项目使用的是原始的jdbc作为数据库的访问,发布到服务器上在运行了一段时间之后总是会出现无法访问的情况,登录到服务器,查看tomcat日志发现总是报如下的错误. Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source rejected establishment of connection, message from server: "Too man

编写自己的jdbc数据库连接池

1.为什么要使用数据库连接池 在使用jdbc的一般开发中,每次都要从数据库获取连接,典例的查询的做法如下: Connection conn = null; PreparedStatement st = null; ResultSet rs = null; try{ Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/tes

在JAVA中实现JDBC数据库连接池

[转自e良师益友网]Java程序员都很羡慕Windows ADO ,只需要new Connection 就可以直接从数据库连接池中返回Connection.并且 ADO Connection 是线程安全的,多个线程可以共用一个Connection,所以ASP程序一般都把getConnection 放在 Global.asa 文件中,在 IIS 启动时建立数据库连接.ADO 的Connection 和Result 都有很好的缓冲,并且很容易使用.推荐学习尚硅谷JDBC视频教程. 其实我们可以自己写

Java之中JDBC数据库连接池实现方法

作为一名初级Java程序员都很羡慕Windows ADO ,只需要new Connection 就可以直接从数据库连接池中返回Connection.并且 ADO Connection 是线程安全的,多个线程可以共用一个Connection,所以ASP程序一般都把getConnection 放在 Global.asa 文件中,在 IIS 启动时建立数据库连接.ADO 的Connection 和Result 都有很好的缓冲,并且很容易使用. 其实我们可以自己写一个JDBC数据库连接池. 写JDBC

数据库连接池

声明:本栏目所使用的素材都是凯哥学堂VIP学员所写,学员有权匿名,对文章有最终解释权:凯哥学堂旨在促进VIP学员互相学习的基础上公开笔记. 数据库连接池简介: 数据库连接对象是有限资源,所以数据库连接池是用于负责分配.管理和释放数据库连接对象,它允许应用程序重复使用一个现有的数据库连接对象,而不是再重新建立一个:这一点实际上和线程池的概念差不多.数据库连接池会释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏,这项技术能明显提高对数据库操作的性能. 不使用

【转载】高性能数据库连接池的内幕

原文:高性能数据库连接池的内幕 中生代技术群分享第三十一期 讲师:何涛 编辑:友强 注:完美修订版 摘要:如何打造高性能的数据库连接池框架,可以从哪些角度进行优化,连接池的大量优化实践如何为你的系统保驾护航,本专题将带你走进连接池的世界,为你一一揭晓.    何涛 唯品会平台架构师 何涛,现任职于唯品会平台架构部,要负责数据访问层,网关,数据库中间件,平台框架等开发设计工作.在数据库性能优化,架构设计等方面有着大量的经验积累.热衷于高可用,高并发及高性能的架构研究. 大家可能会有这样疑问:连接池

高性能数据库连接池的内幕

摘要:如何打造高性能的数据库连接池框架,可以从哪些角度进行优化,连接池的大量优化实践如何为你的系统保驾护航,本专题将带你走进连接池的世界,为你一一揭晓.    何涛 唯品会平台架构师 何涛,现任职于唯品会平台架构部,要负责数据访问层,网关,数据库中间件,平台框架等开发设计工作.在数据库性能优化,架构设计等方面有着大量的经验积累.热衷于高可用,高并发及高性能的架构研究. 大家可能会有这样疑问:连接池类似于线程池或者对象池,就是一个放连接的池子,使用的时候从里面拿一个,用完了再归还,功能非常简单,有

谈谈数据库连接池

前言: 最近又在为暑假的实习奔波...今天的面试被问到连接池有没有使用过,一时竟然哑口(简历上写的可以熟悉mysql啊~).回来反思总结了一下,然后又看了20分钟网上视频.为防止下次面试又出糗,于是便有了这篇随笔~ l 为什么使用数据库连接池: 为了避免每次访问数据库的时候都需要重新建立新的连接而影响运行速度,在实际的项目中通常使用数据库连接池来统一调配,从而提高数据库的访问效率. l 原理示意图: l 下载解压 l 用浏览器查看文档doc下的index.html文件 l 常见2种连接方式 (1

Springboot默认数据库连接池及常用属性

Springboot默认数据库连接池为 Tomcat JDBC Pool ,常用的属性见下表: 属性 描述 默认值 defaultAutoCommit 连接池中创建的连接默认是否自动提交事务 驱动的缺省值 defaultReadOnly 连接池中创建的连接默认是否为只读状态 - defaultCatalog 连接池中创建的连接默认的 catalog - driverClassName 驱动类的名称 - username 数据库账户 - password 数据库密码 - maxActive 连接池