数据库连接池 DBCP和c3p0数据库连接池

你的名字 2022-12-26 07:29 297阅读 0赞

微笑" class="reference-link">一、数据库连接池微笑微笑

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和 Sprint 框架使用的都是该数据源

创建连接池对象

方法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 该文件需要放在类路径下

  1. <!—- 默认配置 –->
  2. <propertyname="initialPoolSize">5</property>
  3. <propertyname="maxPoolSize">15</property>
  4. <propertyname="driverClass">com.mysql.jdbc.Driver</property>
  5. <propertyname="jdbcUrl">jdbc:mysql://localhost:3306/jdbc3</property>
  6. <propertyname="user">root</property>
  7. <propertyname="password">root</property>

  1. <propertyname="initialPoolSize">5</property>
  2. <propertyname="maxPoolSize">15</property>
  3. <propertyname="driverClass">com.mysql.jdbc.Driver</property>
  4. <propertyname="jdbcUrl">jdbc:mysql://localhost:3306/jdbc3</property>
  5. <propertyname="user">root</property>
  6. <propertyname="password">root</property>

三、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 {

  1. // 获得连接
  2. conn =getConnection();
  3. // 预编译sql
  4. pstmt =conn.prepareStatement(sql);
  5. // 将参数设置进去
  6. **for**(**int** i=0; params!=**null**&&i<params.length; i++) \{
  7. pstmt.setObject(i+1,params\[i\]);
  8. \}
  9. // 发送sql
  10. **int** num = pstmt.executeUpdate();
  11. **return** num;

} finally {

  1. // 释放资源
  2. 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 {

  1. // 获得连接
  2. conn =getConnection();
  3. // 预编译sql
  4. pstmt =conn.prepareStatement(sql);
  5. // 将参数设置进去
  6. **for**(**int** i=0; params!=**null**&&i<params.length;i++) \{
  7. pstmt.setObject(i+1,params\[i\]);
  8. \}
  9. // 发送sql
  10. rs =pstmt.executeQuery();
  11. // 不知道别人想如何处理结果集
  12. // 干脆想别人所要一个结果集的处理器
  13. // 为了让当前代码继续,定义一个结果集处理器接口
  14. // 策略模式,规定算法,具体的算法留给将来的调用者实现
  15. Object obj =rsh.handle(rs);
  16. **return** obj;

} finally {

  1. // 释放资源
  2. release(conn,pstmt, rs);

}

}

结果集处理器接口

public interface ResultSetHandler {

// 处理结果集的方法

public Objecthandle(ResultSet rs);

}

实现类:

BeanListHandler

public class BeanListHandler implements ResultSetHandler{

private Classclazz;

publicBeanListHandler(Class clazz) {

  1. this.clazz =clazz;

}

public Objecthandle(ResultSet rs) {

  1. try \{
  2. // 取出结果集所有的记录,封装到bean,存入list返回
  3. List list= new ArrayList();
  4. while(rs.next()) \{
  5. Objectbean = clazz.newInstance();
  6. // 获得元数据
  7. ResultSetMetaDatametaData = rs.getMetaData();
  8. // 获得列的数量
  9. intcount = metaData.getColumnCount();
  10. // 遍历列
  11. for(inti=1; i<=count; i++) \{
  12. // 取列名
  13. StringcolumnName = metaData.getColumnName(i);
  14. // 取这列的值
  15. Objectvalue = rs.getObject(columnName);
  16. // 反射出属性
  17. Fieldfield = clazz.getDeclaredField(columnName);
  18. // 设置属性
  19. field.setAccessible(true);
  20. field.set(bean,value);
  21. \}
  22. // 加入list
  23. list.add(bean);
  24. \}
  25. returnlist;
  26. \} catch(Exception e) \{
  27. throw newRuntimeException(e);
  28. \}

}

}

BeanHandler

public class BeanHandler implements ResultSetHandler {

private Classclazz;

publicBeanHandler(Class clazz) {

  1. this.clazz =clazz;

}

public Objecthandle(ResultSet rs) {

  1. // 不知道有几列数据,不知道列名,不知道封装到什么样的bean
  2. // 表的列明和javabean的字段名一致
  3. try \{
  4. if(rs.next())\{
  5. // 创建bean
  6. Objectbean = clazz.newInstance();
  7. // 封装数据
  8. // 获得结果集的元数据
  9. ResultSetMetaDatametaData = rs.getMetaData();
  10. intcount = metaData.getColumnCount();
  11. // 迭代取每一列的数据
  12. for(inti=1; i<=count; i++) \{
  13. // 获得列名 username
  14. StringcolumnName = metaData.getColumnName(i);
  15. // 获得数据ddd
  16. Objectvalue = rs.getObject(columnName);
  17. // 根据列名反射出映射的属性 username
  18. Fieldfield = clazz.getDeclaredField(columnName);
  19. // 为属性赋值
  20. field.setAccessible(true);
  21. field.set(bean,value);
  22. \}
  23. returnbean;
  24. \}
  25. return null;
  26. \} catch(Exception e) \{
  27. throw newRuntimeException(e);
  28. \}

}

}

ArrayHandler

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

public class ArrayHandler implements ResultSetHandler {

public Objecthandle(ResultSet rs) {

  1. try \{
  2. if(rs.next()) \{
  3. // 指向了第一行的记录
  4. // 获得元数据
  5. ResultSetMetaDatametaData = rs.getMetaData();
  6. // 获得列数
  7. intcount = metaData.getColumnCount();
  8. // 创建数组
  9. Object\[\]arr = new Object\[count\];
  10. // 迭代所有列的值,存入数组
  11. for(inti=1; i<=count; i++) \{
  12. Objectvalue = rs.getObject(i); // 获得指定列的值
  13. arr\[i-1\]= value;
  14. \}
  15. returnarr;
  16. \}
  17. return null;
  18. \} catch(Exception e) \{
  19. throw newRuntimeException(e);
  20. \}

}

}

批处理

处理大数据

Clob Character large Object

text

Blob binary large object

发表评论

表情:
评论列表 (有 0 条评论,297人围观)

还没有评论,来说两句吧...

相关阅读

    相关 数据库连接(C3P0DBCP)

    数据库连接是一种关键的、有限的、昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标。在这

    相关 C3p0-数据库连接

    数据库链接池 数据库连接池的概念 数据库连数据库接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而再不是重新建立一个。 数据库链

    相关 常用数据库连接dbcp/c3p0/druid

    数据库连接的建立和关闭是极耗费系统资源的操作,频繁的打开、关闭连接,将造成系统性能下降。数据库连接池的解决方案是:当应用程序启动时,系统主动建立足够的数据库连接,并将这些连接组