一、数据库连接池

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

#<!--

-->

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

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

  1. Apache中配置数据库连接池(数据源)

    由于基于HTTP协议的Web程序是无状态的,因此,在应用程序中使用JDBC时,每次处理客户端请求都会重新建立数据库链接,如果客户端的请求频繁的话,这将会消耗非常多的资源,因此,在Tomcat中提供了数 ...

  2. 采用c3p0数据库连接池底层是jdbc的数据库的增删改查

    1.新建dbutils包,里面是JdbcUtils类: package cn.com.xxx.xxx.dbutil; import java.sql.Connection; import java.s ...

  3. Spring-Boot-2.0.0-M1版本将默认的数据库连接池从tomcat jdbc pool改为了hikari

    spring-configuration-metadata.json spring-boot-autoconfigure-2.0.0.M7.jar!/META-INF/spring-configura ...

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

    前段时间,接手一个项目使用的是原始的jdbc作为数据库的访问,发布到服务器上在运行了一段时间之后总是会出现无法访问的情况,登录到服务器,查看tomcat日志发现总是报如下的错误. Caused by: ...

  5. MYSQL 之 JDBC(十五):数据库连接池

    在使用开发基于数据库的web程序时,传统的模式基本是按一下步骤: 在主程序(如servlet.bean)中建立数据库连接 进行sql操作 断开数据库连接 这种模式开发存在各种各样的问题,最重要的是:数 ...

  6. JAVA之JDBC数据库连接池总结篇

    JDBC数据库连接池 一.JDBC数据库连接池的必要性 二.数据库连接池技术 三.多种开源的数据库连接池 3.1 C3P0数据库连接池 3.2 DBCP数据库连接池 3.3 Druid(德鲁伊)数据库 ...

  7. JAVA和C#中数据库连接池原理与应用

    JAVA和C#中数据库连接池原理 在现在的互联网发展中,高并发成为了主流,而最关键的部分就是对数据库操作和访问,在现在的互联网发展中,ORM框架曾出不穷, 比如:.Net-Core的EFCore.Sq ...

  8. java通过数据库连接池链接oracle

    开发工具:Eclipse J2EE 3.6 运行环境:jdk1.6 部署环境:Tomcat7 数据库连接池用的是dbcp,网上download下来的三个jar包. 把数据库连接池包和jdbc的包放到t ...

  9. mybatis学习三 数据库连接池技术

    1.在内存中开辟一块空间,存放多个数据库连接对象.就是Connection的多个实例2. 连接池技术有很多,c3p0,dbcp,druid,以及JDBC Tomcat Pool, JDBC Tomca ...

随机推荐

  1. 2014-10-30NOIP复习题1

    Problem 1 Graph (graph.cpp/c/pas) [题目描述] 给出 N 个点,M 条边的有向图,对于每个点 v,求 A(v) 表示从点 v 出发,能到达的编号最大的点. [输入格式 ...

  2. [IOI1998] Pictures

    用线段树维护区间最小值和最小值个数来求一段区间里0的个数,把横的和竖的边分别拿出来,排序,然后每次查一下重复部分的长度即可 #include<iostream> #include<c ...

  3. Django中Form的基本使用

    from django import forms from django.forms import fields class UserInfo(forms.Form): username = fiel ...

  4. substr和substring的区别

    substr和substring两个都是截取字符串的. 两者有相同点,如果只是写一个参数,两者的作用都是一样的:就是截取字符串当前下标以后直到字符串最后的字符串片段. 例如:`var a=”abcde ...

  5. Python笔记(一)——打印输出

    一.输出语句input    输出语句print 例:用户输入 username = input("username:") #变量名 显示的字符 password = input( ...

  6. AleNet模型笔记

    谁创造了AlexNet? AlexNet是有Hinton大神的弟子Alex Krizhevsky提出的深度卷积神经网络.它可视为LeNet的更深更宽的版本. AlexNet主要用到的技术 成功使用Re ...

  7. 用burpsuite暴力破解后台

    [实验原理] Burp Suite是Web应用程序测试的最佳工具之一,其多种功能执行各种任务.请求的拦截和修改,扫描web应用程序漏洞,以暴力破解登录表单,执行会话令牌等多种的随机性检查. Burp ...

  8. js数组排序,支持正反排序以及多维度排序

    工作中遇到js数组排序问题,数组中存储的都是对象,于是就百度了下,利用别人的代码进行修改,最终完成可以倒序.反序,可以进行多维度排序的功能源码如下: /** * js数组排序 支持数字和字符串 * @ ...

  9. 常见压缩格式分析,及 Linux 下的压缩相关指令

    可先浏览加粗部分 一.常见压缩档 *.zip | zip 程式壓縮打包的檔案: (很常见,但是因为不包含文件名编码信息,跨平台可能会乱码) *.rar | winrar 程序压缩打包的档案:(在win ...

  10. Docker多台物理主机之间的容器互联

    Docker 默认的桥接网卡是 docker0.它只会在本机桥接所有的容器网卡,举例来说容器的虚拟网卡在主机上看一般叫做 veth* 而 Docker 只是把所有这些网卡桥接在一起,如下: [root ...