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
#<!--
秒
-->
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优化的更多相关文章
- Apache中配置数据库连接池(数据源)
由于基于HTTP协议的Web程序是无状态的,因此,在应用程序中使用JDBC时,每次处理客户端请求都会重新建立数据库链接,如果客户端的请求频繁的话,这将会消耗非常多的资源,因此,在Tomcat中提供了数 ...
- 采用c3p0数据库连接池底层是jdbc的数据库的增删改查
1.新建dbutils包,里面是JdbcUtils类: package cn.com.xxx.xxx.dbutil; import java.sql.Connection; import java.s ...
- 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 ...
- JDBC整合c3p0数据库连接池 解决Too many connections错误
前段时间,接手一个项目使用的是原始的jdbc作为数据库的访问,发布到服务器上在运行了一段时间之后总是会出现无法访问的情况,登录到服务器,查看tomcat日志发现总是报如下的错误. Caused by: ...
- MYSQL 之 JDBC(十五):数据库连接池
在使用开发基于数据库的web程序时,传统的模式基本是按一下步骤: 在主程序(如servlet.bean)中建立数据库连接 进行sql操作 断开数据库连接 这种模式开发存在各种各样的问题,最重要的是:数 ...
- JAVA之JDBC数据库连接池总结篇
JDBC数据库连接池 一.JDBC数据库连接池的必要性 二.数据库连接池技术 三.多种开源的数据库连接池 3.1 C3P0数据库连接池 3.2 DBCP数据库连接池 3.3 Druid(德鲁伊)数据库 ...
- JAVA和C#中数据库连接池原理与应用
JAVA和C#中数据库连接池原理 在现在的互联网发展中,高并发成为了主流,而最关键的部分就是对数据库操作和访问,在现在的互联网发展中,ORM框架曾出不穷, 比如:.Net-Core的EFCore.Sq ...
- java通过数据库连接池链接oracle
开发工具:Eclipse J2EE 3.6 运行环境:jdk1.6 部署环境:Tomcat7 数据库连接池用的是dbcp,网上download下来的三个jar包. 把数据库连接池包和jdbc的包放到t ...
- mybatis学习三 数据库连接池技术
1.在内存中开辟一块空间,存放多个数据库连接对象.就是Connection的多个实例2. 连接池技术有很多,c3p0,dbcp,druid,以及JDBC Tomcat Pool, JDBC Tomca ...
随机推荐
- [USACO12OPEN]书架Bookshelf
Description 当农夫约翰闲的没事干的时候,他喜欢坐下来看书.多年过去,他已经收集了 N 本书 (1 <= N <= 100,000), 他想造一个新的书架来装所有书. 每本书 i ...
- ●线段树的三个题(poj 3225,hdu 1542,hdu 1828)
●poj 3225 Help with Intervals(线段树区间问题) ○赘述题目 给出以下集合操作: 然后有初始的一个空集S,和以下题目给出的操作指令,并输入指令: 要求进行指令操作后,按格式 ...
- POJ2513 欧拉 + 字典树
POJ 2513 有N根木棒,一根木棒有2头,我们把每头涂色(相同或不同),如果2根木棒有相同颜色的一端就可以连接,颜色全部不同就不能连接,现在给你N根木棒以及它们的颜色,问最后能不能链接成1条链. ...
- ●BZOJ 2560 串珠子
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2560 题解: 容斥,状压计数dp 首先求出一个数组 g[s] 表示集合内的点的连边方案数(两 ...
- Linux input子系统 io控制字段【转】
转自:http://www.cnblogs.com/leaven/archive/2011/02/12/1952793.html http://blog.csdn.net/guoshaobei/arc ...
- HashMap实现原理和源码解析
哈希表(hash table)也叫散列表,是一种非常重要的数据结构.许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,本文会对java集合框架中的对应实现HashMap的 ...
- Linux学习之CentOS(二)--初识linux的一些常用命令(基础命令)
初次学习linux系统,首先也得会一些linux的基本命令.至少要先学会开启和关闭系统吧!我称为 基础命令! linux命令是对Linux系统进行管理的命令.对于Linux系统来说,无论是中央处理器. ...
- 利用gulp把本地文件移动到指定待发布文件夹
一.目标 把本地的文件移动到待发布的文件中,把static_grab文件中file.txt所列文件列表移动到beta对应文件夹中: 二.实现 var gulp = require('gulp'), w ...
- SUSE11虚拟机安装与Oracle 11g安装
SUSE11虚拟机安装与Oracle 11g安装 本文中所需所有参数均位于文末附录中 新建虚拟机,选择SUSE11 64位 启动虚拟机后,选择第二项安装 选择语言 跳过CD检查 选择全新安装 选择默认 ...
- python 的字符串驻留机制
我们都知道python中的引用计数机制,相同对象的引用其实都是指向内存中的同一个位置,这个也叫做“python的字符串驻留机制”.其他的就不多说了,自行研究. 重点!!!!!! python的引用计数 ...