1.在使用开发基于数据库的web程序时,传统的模式基本是按以下步骤:
-在主程序servlet, beans 中建立数据库连接
-进行sql操作
-断开数据库连接
2.该模式存在的问题:
- 因为普通的JDBC数据库连接使用DriverManager来获取,每次建立连接都要将Connection加载到内存中,再验证用户名和密码。需要数据 库连接时,就向数据库要求一个,执行完成再断开连接。当请求连接基数过大时,频繁的数据库连接操作会占用很多系统资源,可能导致服务器崩溃。
- 对于每一次数据库连接,使用完成后都得断开。
- 不能控制被创建的连接对象数。
3.数据库连接池技术(享元模式)
-基本思想: 为数据库连接建立一个“缓冲池”,预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕后再放回去。
-数据库连接池负责分配,管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。
-数据库连接池在初始化时,创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数来设定的。无论这些数据库连接是否被使用,连接池都将一直保证至少有这么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数时,这些请求会被加进等待队列。
4.工作原理图
优点:
-资源重用
-更快的反应速度
-新的资源分配手段
5.多种开源的数据库连接池
-JDBC的数据库连接池使用javax.sql.DataSource 来表示,DataSource只是一个接口,该接口通常由服务器(Weblogic,WebSphere,Tomcat)提供实现
-其他的开源组织提供的实现有:
1.DBCP:速度相对c3p0较快,但存在bug,Hibernate3不再提供支持。
2.C3P0: 速度较慢,稳定性还可以。
3.Proxool: 稳定性较c3p0差一些。
4.BoneCP:速度快。
5.Druid: 阿里提供的数据库连接池,集DBCP,C3p0,Proxool优点于一身的数据库连接池,速度不确定是否有BoneCP快
-DataSource通常被称为数据源,包含连接池和连接池管理两部分,习惯上也把DataSource称为连接池。
-DataSource取代了用DriverManager来获取Connection,获取速度更快,大幅提升数据库访问速度。
//C3P0数据池的两种连接方式,现在基本都有Druid数据库连接池,不用这个
package DataPool;
import Bean.CetDAO;
import Bean.UserDAO;
import User.CetStu;
import User.UserInfo;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.Test;
import java.beans.PropertyVetoException;
import java.sql.Connection;
/**
* @author Vodka
* @date 2021/07//11:25
*/
public class C3P0 {
//方式一:直接输入用户信息进行连接
// @Test
// public void C3P0TestOne (){
// ComboPooledDataSource cpds = new ComboPooledDataSource();
// try {
// //获取c3p0数据库连接池
// cpds.setDriverClass("com.mysql.cj.jdbc.Driver");
// cpds.setJdbcUrl("jdbc:mysql://localhost:3306/iot?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8&&rewriteBatchedStatements=true");
// cpds.setUser("vodka");
// cpds.setPassword("55445445");
//
// // 通过设置相关参数,对数据库连接池进行管理
// // 设置初始时数据库连接池中的连接数的上下限
// cpds.setInitialPoolSize(15);
// cpds.setMaxPoolSize(30);
//
// Connection conn = cpds.getConnection();
// System.out.println(conn);
//
// //销毁c3p0数据库连接池,一般都不这么干
DataSources.destroy(cpds);
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// 方式二:使用配置文件进行连接
//建立连接池,应该建立在所有要用它的类的外部,这样才能实现共享,而不是一个类就建立一个池
private static ComboPooledDataSource cpds = new ComboPooledDataSource("helloC3p0");
public static void main(String []args){
CetDAO cet = new CetDAO();
try {
Connection conn = cpds.getConnection();
CetStu CS = cet.QueryStu(conn,2);
System.out.println(CS);
}catch (Exception e){
e.printStackTrace();
}
}
}
//c3p0的XML文件
<?xml version="1.0" encoding="ISO-8859-1"?>
<c3p0-config>
<named-config named="helloC3p0">
<!-- 提供获取连接的4个基本信息-->
<property name="DriverClass">com.mysql.cj.jdbc.Driver</property>
<property name="JdbcUrl">jdbc:mysql://localhost:3306/iot?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8&&rewriteBatchedStatements=true</property>
<property name="UserName">xxxxx</property>
<property name="Password">6515545454</property>
<!-- 进行数据库连接池管理的基本信息-->
<!-- 当数据库连接池的连接数不够时,c3p0默认向数据库服务器申请增加的连接数-->
<property name="AcquireIncrement">5</property>
<property name="InitialPoolSize">15</property>
<property name="MaxPoolSize">50</property>
<property name="MinPoolSize">15</property>
<property name="MaxStatements">100</property>
<property name="MaxStatementsPerConnection">10</property>
</named-config>
</c3p0-config>
//使用Druid连接池进行数据库连接,并管理连接池
package DataPool;
import Bean.CetDAO;
import User.CetStu;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.mchange.v2.c3p0.DataSources;
import org.junit.Test;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.Timestamp;
import java.util.Date;
import java.util.Properties;
/**
* @author Vodka
* @date 2021/07//13:13
*/
public class Druid {
@Test
public void DruidTest(){
try {
Properties pros = new Properties();
InputStream IS = ClassLoader.getSystemClassLoader().getResourceAsStream("DruidTestInfo.properties");
pros.load(IS);
DataSource DS = DruidDataSourceFactory.createDataSource(pros);
Connection conn = DS.getConnection();
CetDAO Cdao = new CetDAO();
CetStu cs = new CetStu(4,578,new Timestamp(new Date().getTime()),"4569","119011","莎伊儆百","Tokoyo");
Cdao.InCET(conn,cs);
System.out.println(conn);
} catch (Exception e) {
e.printStackTrace();
}
}
}
//Durid连接池的连接配置文件
url=jdbc:mysql://localhost:3306/iot?useSSl=false&serverTimezone=UTC&characterEncoding=UTF-8&&rewriteBatchedStatements=true
driverClassName=com.mysql.cj.jdbc.Driver
username=xxxx
password=sdfasf
initialSize=10
maxActive=30
//在自定义的GetConection工具类中,设置Druid连接池为静态属性,并添加一个静态的构造方法(创建公共连接池),使得其他对象可以获取连接池的连接
package Instrument;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**
* @author Vodka
* @date 2021/07//17:14
*/
public class GetConnection {
/*
*
* 封装获取数据库连接的函数
*
*
*
* */
//没有数据连接池的原始连接
public static Connection getConnection() throws IOException, ClassNotFoundException, SQLException {
//加载配置文件
InputStream IS = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
Properties pros = new Properties();
pros.load(IS);
String User = pros.getProperty("User");
String PassWord = pros.getProperty("PassWord");
String Url = pros.getProperty("Url");
String DriverClass = pros.getProperty("DriverClass");
//利用反射机制,注册驱动,连接数据库
Class.forName(DriverClass);
Connection conn = DriverManager.getConnection(Url,User,PassWord);
if(conn != null) System.out.println("数据库连接成功!");
else System.out.println("数据库连接失败!");
// 返回连接
return conn;
}
//使用公共Druid连接池的连接
private static DataSource PoolOne;
// 静态构造方法创建连接,因为是静态的构造,所以该方法只在类创建实例对象时,构造一次(一个池子)
static {
try{
Properties pros = new Properties();
InputStream IS = ClassLoader.getSystemClassLoader().getResourceAsStream("DruidTestInfo.properties");
pros.load(IS);
PoolOne = DruidDataSourceFactory.createDataSource(pros);
}catch (Exception e){
e.printStackTrace();
}
}
//利用连接池获取连接
public static Connection getConnectionTwo() throws Exception{
return PoolOne.getConnection();
}
/*
* 2.封装关闭流函数
* */
public static void Close(Connection conn , PreparedStatement ps) throws SQLException{
if (conn != null ) conn.close();
if(ps != null) ps.close();
if(conn == null && ps == null) System.out.println("数据库连接已关闭!");
}
//当有查询返回的结果集时,也需要关闭相关资源
public static void CloseResource(Connection conn,PreparedStatement ps, ResultSet rs)throws SQLException{
if(conn != null) conn.close();
if(ps != null) ps.close();
if(rs != null) rs.close();
if(conn == null && ps == null && rs == null) System.out.println("数据库连接已经关闭!");
}
}