一、JDBC连接
1.1 连接过程
连接过程:
1.加载驱动、获取连接对象
2.执行sql
3.关闭连接资源。
1.2 连接分析
1.2.1 频繁操作数据库出现的问题(连接池出现的原因)
缺点:
1.在JDBC中,连接资源是十分宝贵的,mysql仅仅支持几百个连接资源。
2.连接对象的创建和销毁也是十分消耗系统资源。
3.如果频繁的操作数据库,则连接对象也需要频繁的被打开和关闭,严重
消耗系统资源。
假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪
费数据库的资源,并且极易造成数据库服务器内存溢出、拓机。
所以在此情景下,我们引入了连接池技术。
1.2.2 连接的优化
预先创建一组连接,有的时候每次取出一个; 用完后,放回;
1.2.3 连接池的一般参数
驱动名、用户名、密码、初始化连接数、最大连接数、最大空闲时间。
二、连接池
2.1 JDBC1.0 与 JDBC2.0区别
JDBC1.0原来是用DriverManager类产生一个对数据源的连接,
JDBC2.0用一种替代的方法,使用DataSource的实现,代码变得更小巧精灵,也更容易控制。
DataSource接口是更好的连接数据源的方法。
2.2 连接池技术的引入
连接池出现的原因:
创建连接和销毁连接是十分消耗内存资源的,
如果用户频繁操作数据库,则会影响程序的执行效率。
连接池的作用:
管理连接资源,提高效率
2.3 连接池技术的实现
数据源技术包含了连接池技术的实现:
1.现在很多WEB服务器(Weblogic, WebSphere, Tomcat)都提供了DataSoruce
的实现,即数据源的实现。有一些开源组织提供了数据源的独立实现:
2.Sun公司规定,如果是连接池技术,则用户需要实现DataSource接口(javax.sql.DataSource)。
数据源技术包含了连接池技术的实现。
连接池技术(数据源技术):
1.自定义连接池
2.使用第三方连接池
DBCP 数据库连接池 (tomcat)
C3P0 数据库连接池 (hibernate)
3.使用服务器自带的连接池
三、自定义连接池
public class MyPool {
//默认连接数
private int init_num=3;
//最大连接数
private int max_num=4;
//当前连接数
private int current_num=3;
//连接池
private LinkedList<Connection> pool=new LinkedList<Connection>();
/**
* 初始化连接池
*/
public MyPool() {
for(int i=0;i<init_num;i++) {
pool.addLast(createCon());
}
}
/**
* 创建连接对象
*
* @return
*/
@Test
public Connection createCon() {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/day11", "root", "root");
/** 创建代理类 **/
Connection proxy=(Connection)Proxy.newProxyInstance(Connection.class.getClassLoader(),new Class[] {Connection.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
if("close".equals(methodName)) {
System.out.println("调用了close方法");
//当用户调用close方法时,记录连接数也要发生改变
current_num--; //记录当前连接数
Object result = method.invoke(conn, args);
return result;
}
return method.invoke(conn, args);
}
});
return proxy;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 获取连接
*
* @return
*/
public Connection getConn() {
//1.如果连接池中有连接对象,则从连接池中获取
if(pool.size()>0) {
return pool.removeFirst();
}
//2.当连接池中没有连接对象,则需判断当前连接数是否大于最大连接数
if(current_num < max_num) {
current_num++; //记录当前连接数
return createCon();
}
throw new RuntimeException("已达到最大连接数...");
}
/**
* 释放连接
*
* @param conn
*/
public void releaseConn(Connection conn) {
//当连接池中连接数小于初始化连接数
if(pool.size()<3) {
pool.addLast(conn);
}
//当连接池中连接数大于初始化连接数
try {
conn.close();
current_num--;
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws SQLException {
MyPool pool=new MyPool();
Connection conn = pool.getConn();
Connection conn2 = pool.getConn();
Connection conn3 = pool.getConn();
Connection conn4= pool.getConn();
conn4.close(); //该方法触发了current_num--
System.out.println(pool.current_num);
}
}
四、DBCP连接池
4.1 使用DBCP连接池的引入的jar包
DBCP 是 Apache 软件基金组织下的开源连接池实现,使用DBCP数据源,应用程序
应在系统中增加如下两个 jar 文件:
•Commons-dbcp.jar:连接池的实现
•Commons-pool.jar:连接池实现的依赖库
4.2 使用DBCP连接池
核心类:BasicDataSource
硬编码方式:
BasicDataSource dataSouce = new BasicDataSource();
dataSouce.setUrl("jdbc:mysql:///jdbc_demo"); //数据库连接字符串
dataSouce.setDriverClassName("com.mysql.jdbc.Driver");
配置方式:
DataSource dataSouce = BasicDataSourceFactory.createDataSource(Demo.class.getResourceAsStream("/db.properties"));
db.properties
url=jdbc:mysql:///jdbc_demo
driverClassName=com.mysql.jdbc.Driver
username=root
password=root
initialSize=3
maxActive=6
maxIdle=3000
4.2.1 硬编码方式使用DBCP连接池
public class App_DBCP {
// 1. 硬编码方式实现连接池
@Test
public void testDbcp() throws Exception {
// DBCP连接池核心类
BasicDataSource dataSouce = new BasicDataSource();
// 连接池参数配置:初始化连接数、最大连接数 / 连接字符串、驱动、用户、密码
dataSouce.setUrl("jdbc:mysql:///jdbc_demo"); //数据库连接字符串
dataSouce.setDriverClassName("com.mysql.jdbc.Driver"); //数据库驱动
dataSouce.setUsername("root"); //数据库连接用户
dataSouce.setPassword("root"); //数据库连接密码
dataSouce.setInitialSize(3); // 初始化连接
dataSouce.setMaxActive(6); // 最大连接
dataSouce.setMaxIdle(3000); // 最大空闲时间
// 获取连接
Connection con = dataSouce.getConnection();
con.prepareStatement("delete from admin where id=3").executeUpdate();
// 关闭
con.close();
}
4.2.2 配置方式使用DBCP连接池
db.properties
url=jdbc:mysql:///jdbc_demo
driverClassName=com.mysql.jdbc.Driver
username=root
password=root
initialSize=3
maxActive=6
maxIdle=3000
[配置方式实现DBCP连接池, 配置文件中的key与BaseDataSouce中的属性一样]
@Test
// 2. 【推荐】配置方式实现连接池 , 便于维护
public void testProp() throws Exception {
// 加载prop配置文件
Properties prop = new Properties();
// 获取文件流
InputStream inStream = App_DBCP.class.getResourceAsStream("db.properties");
// 加载属性配置文件
prop.load(inStream);
// 根据prop配置,直接创建数据源对象
DataSource dataSouce = BasicDataSourceFactory.createDataSource(prop);
// 获取连接
Connection con = dataSouce.getConnection();
con.prepareStatement("delete from admin where id=4").executeUpdate();
// 关闭
con.close();
}
}
五、C3P0连接池
5.1 使用C3P0连接池的引入的jar包
C3P0连接池:
最常用的连接池技术!Spring框架,默认支持C3P0连接池技术!
使用C3P0连接池需要导包:
c3p0-0.9.1.2.jar
5.2 使用C3P0连接池
核心类:CombopooledDataSource
硬编码方式:
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/jdbc_demo");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
XML配置方式:
自动加载src下c3p0的配置文件【c3p0-config.xml】
//1.使用默认数据配置进行连接
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//2.指定数据配置进行连接
ComboPooledDataSource dataSource = new ComboPooledDataSource("name");
5.2.1 硬编码方式使用C3P0连接池
@Test
//1. 硬编码方式,使用C3P0连接池管理连接
public void testCode() throws Exception {
// 创建连接池核心工具类
ComboPooledDataSource dataSource = new ComboPooledDataSource();
// 设置连接参数:url、驱动、用户密码、初始连接数、最大连接数、最大空闲时间
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/jdbc_demo");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setUser("root");
dataSource.setPassword("root");
dataSource.setInitialPoolSize(3);
dataSource.setMaxPoolSize(6);
dataSource.setMaxIdleTime(1000);
// ---> 从连接池对象中,获取连接对象
Connection con = dataSource.getConnection();
// 执行更新
con.prepareStatement("delete from admin where id=7").executeUpdate();
// 关闭
con.close();
}
5.2.2 XML配置方式使用C3P0连接池
C3P0连接池会自动加载src目录下的c3p0-config.xml配置文件。
C3P0连接池的XML可以配置多个数据源。
c3p0-config.xml
放在classpath的根目录下。
<c3p0-config>
<!-- 默认数据库 -->
<default-config>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/day11</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="initialPoolSize">3</property>
<property name="maxPoolSize">6</property>
<property name="maxIdleTime">1000</property>
</default-config>
<!-- 可以配置多数据源 -->
<named-config name="db33">
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="initialPoolSize">3</property>
<property name="maxPoolSize">6</property>
<property name="maxIdleTime">1000</property>
</named-config>
</c3p0-config>
使用
//1. XML配置方式,使用C3P0连接池管理连接
//读取默认数据库配置进行连接
public void testXML() throws Exception {
// 自动加载src下c3p0的配置文件【c3p0-config.xml】
ComboPooledDataSource dataSource = new ComboPooledDataSource();// 使用默认的配置
// 获取连接
Connection con = dataSource.getConnection();
// 执行更新
con.prepareStatement("delete from admin where id=5").executeUpdate();
// 关闭
con.close();
}
//读取指定数据库配置进行连接
public void testXML() throws Exception {
ComboPooledDataSource dataSource = new ComboPooledDataSource("db33");// 使用默认的配置
Connection con = dataSource.getConnection();
con.prepareStatement("delete from admin where id=5").executeUpdate();
con.close();
}