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 ...
随机推荐
- [USACO 13NOV]No Change
Description Farmer John is at the market to purchase supplies for his farm. He has in his pocket K c ...
- [HAOI2011]向量
题目描述 给你一对数a,b,你可以任意使用(a,b), (a,-b), (-a,b), (-a,-b), (b,a), (b,-a), (-b,a), (-b,-a)这些向量,问你能不能拼出另一个向量 ...
- 2015 多校联赛 ——HDU5402(模拟)
For each test case, in the first line, you should print the maximum sum. In the next line you should ...
- 抽象方法不能是static或native或synchroniz
abstract 是抽象了,只有声明,没有具体的实现方法 static是静态的,是一种属于类而不属于对象的方法或者属性,而我们知道,类其实也是一个对象,他是在class文件加载到虚拟机以后就会产生的对 ...
- if(/专线$/.test(name))讲解
如图: 这条语句的意思是:匹配以"专线"结尾的name字符串,满足条件的返回true,否则返回false
- Android绘制文字时垂直居中
canvas.drawText(String text, float x, float y, Paint paint); 是Android中绘制文本的方法,其中的x代表文字绘制时在X轴的起始点,而y是 ...
- 提高Mysql查询速度的一些建议(转).
1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索 ...
- Java finalize方法使用
<JAVA编程思想>: Java提供finalize()方法,垃圾回收器准备释放内存的时候,会先调用finalize(). (1).对象不一定会被回收. (2).垃圾回收不是析构函数. ( ...
- MySQL数据类型DECIMAL用法
MySQL DECIMAL数据类型用于在数据库中存储精确的数值.我们经常将DECIMAL数据类型用于保留准确精确度的列,例如会计系统中的货币数据. 要定义数据类型为DECIMAL的列,请使用以下语法: ...
- Ubuntu16.04下安装jdk1.8过程
笔者环境:腾讯云服务器 Ubuntu16.04 x64 一 . 去oracle官网下载对应的jdk 下载地址:http://www.oracle.com/technetwork/java/javase ...