本专栏将从基础开始,循序渐进,讲解数据库的基本概念以及使用,希望大家都能够从中有所收获,也请大家多多支持。
专栏地址: 数据库必知必会
相关软件地址:软件地址
如果文章知识点有错误的地方,请指正!大家一起学习,一起进步。

文章目录

  • 1 自定义连接池
    • 1.1 连接池概念
      • 1.1.1 为什么要使用连接池
      • 1.1.2 生活里面的连接池例子
      • 1.1.3 连接池原理
    • 1.2 自定义连接池-初级版本
    • 1.3 自定义连接池-进阶版本
      • 1.3.1 datasource接口概述
      • 1.3.2 代码实现
      • 1.3.2 编写连接池遇到的问题
    • 1.4 自定义连接池-终极版本
      • 1.4.1 装饰者模式
        • 1.4.1.1 概述
        • 1.4.1.2 装饰者模式的使用
      • 1.4.2 自定义连接池终极版本
        • 1.4.2.1 分析
        • 1.4.2.2 实现
  • 2 第三方连接池
    • 2.1 常用连接池
    • 2.2 C3P0
      • 2.2.1 c3p0介绍
      • 2.2.2 c3p0的使用
        • 2.2.2.1 通过硬编码来编写
        • 2.2.2.2 通过配置文件来编写
        • 2.2.2.3 使用c3p0改写工具类
    • 2.3 DRUID
      • 2.3.1 DRUID介绍
      • 2.3.2 DRUID的使用
      • 2.3.3 通过硬编码方式
      • 2.3.4 通过配置文件方式
      • 2.3.5 使用DruidUtils改写工具类

1 自定义连接池

1.1 连接池概念

1.1.1 为什么要使用连接池

​ Connection对象在JDBC使用的时候就会去创建一个对象,使用结束以后就会将这个对象给销毁了(close),每次创建和销毁对象都是耗时操作,需要使用连接池对其进行优化.

​ 程序初始化的时候,初始化多个连接,将多个连接放入到池(集合)中,每次获取的时候,都可以直接从连接池中进行获取,使用结束以后,将连接归还到池中。

1.1.2 生活里面的连接池例子

  • 老方式:

    ​ 下了地铁需要骑车, 跑去生产一个, 然后骑完之后,直接把车销毁了。

  • 连接池方式 摩拜单车:

    ​ 骑之前, 有一个公司生产了很多的自行车, 下了地铁需要骑车, 直接扫码使用就好了, 然后骑完之后, 还回去。

1.1.3 连接池原理

  1. 程序一开始就创建一定数量的连接,放在一个容器(集合)中,这个容器称为连接池。
  2. 使用的时候直接从连接池中取一个已经创建好的连接对象, 使用完成之后 归还到池子
  3. 如果池子里面的连接使用完了, 还有程序需要使用连接, 先等待一段时间(eg: 3s), 如果在这段时间之内有连接归还, 就拿去使用; 如果还没有连接归还, 新创建一个, 但是新创建的这一个不会归还了(销毁)
  4. 集合选择LinkedList
    • 增删比较快
    • LinkedList里面的removeFirst()和addLast()方法和连接池的原理吻合

使用连接池的目的: 可以让连接得到复用, 避免浪费

1.2 自定义连接池-初级版本

目标

​ 根据连接池的原理, 使用LinkedList自定义连接池

分析

  1. 创建一个类MyDataSource, 定义一个集合LinkedList
  2. 程序初始化的时候, 创建5个连接 存到LinkedList
  3. 定义getConnection() 从LinkedList取出Connection返回
  4. 定义addBack()方法归还Connection到LinkedList

实现

  • JDBCUtils.java
package com.hashnode.utils;import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;public class JDBCUtils {private static String driver;private static String url;private static String user;private static String password;static {try {// 使用Properties对象加载配置文件// 创建Properties对象Properties pro = new Properties();// 读取配置文件中的数据//pro.load(new FileInputStream("my-code\\src\\db.properties"));// 返回的输入流的路径默认到src路径InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");pro.load(is);// 通过pro对象给属性赋值url = pro.getProperty("url");user = pro.getProperty("username");password = pro.getProperty("password");driver = pro.getProperty("driver");// 1.加载驱动Class.forName(driver);} catch (Exception e) {e.printStackTrace();}}/*** 获得连接** @return 连接* @throws Exception*/public static Connection getConnection() throws Exception {// 2.获得连接Connection connection = DriverManager.getConnection(url, user, password);return connection;}/*** 释放资源** @param resultSet* @param statement* @param connection*/public static void release(ResultSet resultSet, Statement statement, Connection connection) {if (resultSet != null) {try {resultSet.close();} catch (SQLException e) {e.printStackTrace();}}if (statement != null) {try {statement.close();} catch (SQLException e) {e.printStackTrace();}}if (connection != null) {try {connection.close();} catch (SQLException e) {e.printStackTrace();}}}
}
  • MyDataSource1.java
package com.hashnode.datapool;import com.hashnode.utils.JDBCUtils;import java.sql.Connection;
import java.util.LinkedList;public class MyDataSource1 {// 1.定义一个LinkedList集合,用来存储初始化的连接private static LinkedList<Connection> list = new LinkedList<>();// 2.初始化5个连接,并存储到集合中static {for (int i = 0; i < 5; i++) {try {// 获得连接Connection connection = JDBCUtils.getConnection();// 添加到集合中list.add(connection);} catch (Exception e) {e.printStackTrace();}}}// 3.定义getAbc方法,用来获得连接public Connection getAbc(){Connection connection = list.removeFirst();return connection;}// 4.定义addBack方法,用来归还连接public void addBack(Connection connection){list.addLast(connection);}// 5.定义getCount方法,返回连接池中连接数量public static int getCount(){return list.size();}
}
  • CRUDTest1.java
package com.hashnode.datapool;import com.hashnode.pojo.User;
import com.hashnode.utils.JDBCUtils;
import org.junit.Test;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;// 测试
public class CRUDTest1 {// 查询记录@Testpublic void select() throws Exception {// 1.创建连接池对象MyDataSource1 dataSource = new MyDataSource1();System.out.println("获得连接之前,连接池中连接的数量:"+MyDataSource1.getCount());// 5// 2.获得连接Connection connection = dataSource.getAbc();// 2.书写sql语句,预编译sql语句,得到预编译对象String sql = "select * from user where id = ?";PreparedStatement ps = connection.prepareStatement(sql);// 3.设置参数ps.setInt(1,3);// 4.执行sql语句ResultSet resultSet = ps.executeQuery();// 封装,处理数据User user = null;while (resultSet.next()){user = new User();user.setId(resultSet.getInt("id"));user.setUsername(resultSet.getString("username"));user.setPassword(resultSet.getString("password"));user.setNickname(resultSet.getString("nickname"));}System.out.println("获得连接之后,连接池中连接的数量:"+MyDataSource1.getCount());// 4System.out.println(user);// 5.释放资源// 归还连接dataSource.addBack(connection);JDBCUtils.release(resultSet,ps,null);System.out.println("归还连接之后,连接池中连接的数量:"+MyDataSource1.getCount());// 5}
}

小结

  1. 创建一个类MyDataSource, 定义一个集合LinkedList
  2. 程序初始化(静态代码块)里面 创建5个连接存到LinkedList
  3. 定义提供Connection的方法
  4. 定义归还Connection的方法

1.3 自定义连接池-进阶版本

目标

​ 实现datasource完成自定义连接池

分析

​ 在初级版本版本中, 我们定义的方法是getAbc(),因为是自定义的,如果改用李四的自定义的连接池,李四定义的方法是getCon(), 那么我们的源码就需要修改, 这样不方便维护,所以sun公司定义了一个接口DataSource,让自定义连接池有了规范。

1.3.1 datasource接口概述

​ Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商(用户)需要让自己的连接池实现这个接口。这样应用程序可以方便的切换不同厂商的连接池!

1.3.2 代码实现

public class MyDataSource2 implements DataSource {// 1.定义一个LinkedList集合,用来存储初始化的连接private static LinkedList<Connection> list = new LinkedList<>();// 2.初始化5个连接,并存储到集合中static {for (int i = 0; i < 5; i++) {try {// 获得连接Connection connection = JDBCUtils.getConnection();// 添加到集合中list.add(connection);} catch (Exception e) {e.printStackTrace();}}}/*// 3.定义getAbc方法,用来获得连接public Connection getAbc(){Connection connection = list.removeFirst();return connection;}*/// 4.定义addBack方法,用来归还连接public void addBack(Connection connection){list.addLast(connection);}// 5.定义getCount方法,返回连接池中连接数量public static int getCount(){return list.size();}@Overridepublic Connection getConnection() throws SQLException {Connection connection = list.removeFirst();return connection;}@Overridepublic Connection getConnection(String username, String password) throws SQLException {return null;}@Overridepublic PrintWriter getLogWriter() throws SQLException {return null;}@Overridepublic void setLogWriter(PrintWriter out) throws SQLException {}@Overridepublic void setLoginTimeout(int seconds) throws SQLException {}@Overridepublic int getLoginTimeout() throws SQLException {return 0;}@Overridepublic Logger getParentLogger() throws SQLFeatureNotSupportedException {return null;}@Overridepublic <T> T unwrap(Class<T> iface) throws SQLException {return null;}@Overridepublic boolean isWrapperFor(Class<?> iface) throws SQLException {return false;}
}// 测试
public class CRUDTest2 {// 查询记录@Testpublic void select() throws Exception {// 1.创建连接池对象DataSource dataSource = new MyDataSource2();System.out.println("获得连接之前,连接池中连接的数量:"+MyDataSource2.getCount());// 5// 2.获得连接Connection connection = dataSource.getConnection();// 2.书写sql语句,预编译sql语句,得到预编译对象String sql = "select * from user where id = ?";PreparedStatement ps = connection.prepareStatement(sql);// 3.设置参数ps.setInt(1,3);// 4.执行sql语句ResultSet resultSet = ps.executeQuery();// 封装,处理数据User user = null;while (resultSet.next()){user = new User();user.setId(resultSet.getInt("id"));user.setUsername(resultSet.getString("username"));user.setPassword(resultSet.getString("password"));user.setNickname(resultSet.getString("nickname"));}System.out.println("获得连接之后,连接池中连接的数量:"+MyDataSource2.getCount());// 4System.out.println(user);// 5.释放资源// 归还连接// 解决办法: 1.向下转型  2.增强Connection的close方法(默认是销毁连接,增强后变成归还连接)((MyDataSource2)dataSource).addBack(connection);JDBCUtils.release(resultSet,ps,null);System.out.println("归还连接之后,连接池中连接的数量:"+MyDataSource2.getCount());// 5}
}

1.3.2 编写连接池遇到的问题

  • 实现DataSource接口后,addBack()不能调用了。
  • 能不能不引入新的api,直接调用之前的connection.close(),但是这个close不是关闭,是归还

解决办法

  • 继承

    • 条件:可以控制父类, 最起码知道父类的名字
  • 装饰者模式

    • 作用:改写已存在的类的某个方法或某些方法
    • 条件:
      • 增强类和被增强类实现的是同一个接口
      • 增强类里面要拿到被增强类的引用
  • 动态代理

1.4 自定义连接池-终极版本

目标

使用装饰者模式改写connection的close()方法, 让connection归还

1.4.1 装饰者模式

1.4.1.1 概述

  • 什么是装饰者模式

    ​ 装饰者模式,是 23种常用的面向对象软件的设计模式之一, 动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更加有弹性的替代方案。

    ​ 装饰者的作用:改写已存在的类的某个方法或某些方法, 增强方法的逻辑

  • 使用装饰者模式需要满足的条件

    • 增强类和被增强类实现的是同一个接口
    • 增强类里面要拿到被增强类的引用

1.4.1.2 装饰者模式的使用

实现步骤:

  1. 增强类和被增强类需要实现同一个接口
  2. 增强类里面需要得到被增强类的引用,
  3. 对于不需要改写的方法,调用被增强类原有的方法。
  4. 对于需要改写的方法写自己的代码
  • 接口:
public interface Star {public void sing();public void dance();
}
  • 被增强的类:
public class AAA implements Star {@Overridepublic void sing() {System.out.println("AAA is sing...");}@Overridepublic void dance() {System.out.println("AAA is dancing...");}
}
  • 增强的类:
public class AAAWrapper implements Star {// 增强类中获得被增强类的引用LiuDeHua ldh;public LiuDeHuaWrapper(LiuDeHua ldh) {this.ldh = ldh;}@Overridepublic void sing() {System.out.println("AAA is sing...");ldh.sing();System.out.println("AAA is practicing...");}@Overridepublic void dance() {// 不增强ldh.dance();}
}
  • 测试

    public class Test {public static void main(String[] args) {// 没有使用装饰者LiuDeHua ldh = new LiuDeHua();//ldh.sing();//ldh.dance();// 使用装饰者AAAWrapper ldhw = new LiuDeHuaWrapper(ldh);ldhw.sing();ldhw.dance();}
    }
    

1.4.2 自定义连接池终极版本

1.4.2.1 分析

​ 增强connection的close()方法, 其它的方法逻辑不改

  1. 创建MyConnection实现Connection
  2. 在MyConnection里面需要得到被增强的connection对象(通过构造方法传进去)
  3. 改写close()的逻辑, 变成归还
  4. 其它方法的逻辑, 还是调用被增强connection对象之前的逻辑

1.4.2.2 实现

  • MyConnection
public class MyConnection implements Connection {// 获得被增强的连接对象的引用Connection con;// 获得连接池LinkedList<Connection> list;public MyConnection(Connection con, LinkedList<Connection> list) {this.con = con;this.list = list;}@Overridepublic void close() throws SQLException {// 归还连接list.addLast(con);}@Overridepublic Statement createStatement() throws SQLException {return con.createStatement();}// 必须写@Overridepublic PreparedStatement prepareStatement(String sql) throws SQLException {return con.prepareStatement(sql);}// 剩余的重写方法,使用被增强的连接对象调用原有方法...// ...
}
  • MyDataSource03
public class MyDataSource3 implements DataSource {// 1.定义一个LinkedList集合,用来存储初始化的连接private static LinkedList<Connection> list = new LinkedList<>();// 2.初始化5个连接,并存储到集合中static {for (int i = 0; i < 5; i++) {try {// 获得连接Connection connection = JDBCUtils.getConnection();// 添加到集合中list.add(connection);} catch (Exception e) {e.printStackTrace();}}}/*// 3.定义getAbc方法,用来获得连接public Connection getAbc(){Connection connection = list.removeFirst();return connection;}*//*// 4.定义addBack方法,用来归还连接public void addBack(Connection connection){list.addLast(connection);}*/// 5.定义getCount方法,返回连接池中连接数量public static int getCount(){return list.size();}@Overridepublic Connection getConnection() throws SQLException {Connection connection = list.removeFirst();// 返回的是被增强的连接对象// 增强MyConnection myConnection = new MyConnection(connection,list);return myConnection;}@Overridepublic Connection getConnection(String username, String password) throws SQLException {return null;}@Overridepublic PrintWriter getLogWriter() throws SQLException {return null;}@Overridepublic void setLogWriter(PrintWriter out) throws SQLException {}@Overridepublic void setLoginTimeout(int seconds) throws SQLException {}@Overridepublic int getLoginTimeout() throws SQLException {return 0;}@Overridepublic Logger getParentLogger() throws SQLFeatureNotSupportedException {return null;}@Overridepublic <T> T unwrap(Class<T> iface) throws SQLException {return null;}@Overridepublic boolean isWrapperFor(Class<?> iface) throws SQLException {return false;}
}
  • JDBCUtils.java
package com.hashnode.utils;import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;public class JDBCUtils {private static String driver;private static String url;private static String user;private static String password;static {try {// 使用Properties对象加载配置文件// 创建Properties对象Properties pro = new Properties();// 读取配置文件中的数据//pro.load(new FileInputStream("my-code\\src\\db.properties"));// 返回的输入流的路径默认到src路径InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");pro.load(is);// 通过pro对象给属性赋值url = pro.getProperty("url");user = pro.getProperty("username");password = pro.getProperty("password");driver = pro.getProperty("driver");// 1.加载驱动Class.forName(driver);} catch (Exception e) {e.printStackTrace();}}/*** 获得连接** @return 连接* @throws Exception*/public static Connection getConnection() throws Exception {// 2.获得连接Connection connection = DriverManager.getConnection(url, user, password);return connection;}/*** 释放资源** @param resultSet* @param statement* @param connection*/public static void release(ResultSet resultSet, Statement statement, Connection connection) {if (resultSet != null) {try {resultSet.close();} catch (SQLException e) {e.printStackTrace();}}if (statement != null) {try {statement.close();} catch (SQLException e) {e.printStackTrace();}}if (connection != null) {try {connection.close();} catch (SQLException e) {e.printStackTrace();}}}
}
  • 测试类

    public class CRUDTest3 {// 查询记录@Testpublic void select() throws Exception {// 1.创建连接池对象DataSource dataSource = new MyDataSource3();System.out.println("获得连接之前,连接池中连接的数量:"+MyDataSource3.getCount());// 5// 2.获得连接Connection connection = dataSource.getConnection();// 返回的是增强的连接对象 MyConnection// 2.书写sql语句,预编译sql语句,得到预编译对象String sql = "select * from user where id = ?";PreparedStatement ps = connection.prepareStatement(sql);// 3.设置参数ps.setInt(1,3);// 4.执行sql语句ResultSet resultSet = ps.executeQuery();// 封装,处理数据User user = null;while (resultSet.next()){user = new User();user.setId(resultSet.getInt("id"));user.setUsername(resultSet.getString("username"));user.setPassword(resultSet.getString("password"));user.setNickname(resultSet.getString("nickname"));}System.out.println("获得连接之后,连接池中连接的数量:"+MyDataSource3.getCount());// 4System.out.println(user);// 5.释放资源// 归还连接//connection.close();// 归还连接JDBCUtils.release(resultSet,ps,connection);System.out.println("归还连接之后,连接池中连接的数量:"+MyDataSource3.getCount());// 5}
    }
    

小结

  1. 创建一个MyConnection实现Connection
  2. 在MyConnection得到被增强的connection对象
  3. 改写MyConnection里面的close()方法的逻辑为归还
  4. MyConnection里面的其它方法 调用被增强的connection对象之前的逻辑
  5. 在MyDataSource03的getConnection()方法里面返回了myConnection(增强的连接对象)(此时调用的是多态,即MyConnection中重写的close方法)

2 第三方连接池

2.1 常用连接池

​ 通过前面的学习,我们已经能够使用所学的基础知识构建自定义的连接池了。其目的是锻炼大家的基本功,帮助大家更好的理解连接池的原理, 但现实是残酷的,我们所定义的 连接池 和第三方的连接池相比,还是显得渺小. 工作里面都会用第三方连接池.

常见的第三方连接池如下:

  • C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。C3P0是异步操作的,所以一些操作时间过长的JDBC通过其它的辅助线程完成。目前使用它的开源项目有Hibernate,Spring等。C3P0有自动回收空闲连接功能
  • 阿里巴巴-德鲁伊druid连接池:Druid是阿里巴巴开源平台上的一个项目,整个项目由数据库连接池、插件框架和SQL解析器组成。该项目主要是为了扩展JDBC的一些限制,可以让程序员实现一些特殊的需求。
  • DBCP(DataBase Connection Pool)数据库连接池,是Apache上的一个Java连接池项目,也是Tomcat使用的连接池组件。dbcp没有自动回收空闲连接的功能。

我们工作里面用的比较多的是:

  • C3P0
  • druid
  • 光连接池

2.2 C3P0

2.2.1 c3p0介绍

  • C3P0是开源免费的连接池,目前使用它的开源项目有:Spring、Hibernate等。使用第三方工具需要导入jar包,c3p0使用时还需要添加配置文件c3p0-config.xml.
  • 使用C3P0需要添加c3p0-0.9.1.2.jar

2.2.2 c3p0的使用

2.2.2.1 通过硬编码来编写

步骤

  1. 拷贝jar
  2. 创建C3P0连接池对象
  3. 从C3P0连接池对象里面获得connection

实现:

package com.hashnode.test;import com.hashnode.pojo.User;
import com.hashnode.utils.JDBCUtils;
import com.mchange.v2.c3p0.ComboPooledDataSource;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;public class C3P0Test1 {public static void main(String[] args) throws Exception {// 1.拷贝c3p0jar包到模块下,并添加到classpath路径中// 2.创建连接池对象ComboPooledDataSource dataSource = new ComboPooledDataSource();// 连接池设置参数dataSource.setDriverClass("com.mysql.jdbc.Driver");dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/hashnode");dataSource.setUser("root");dataSource.setPassword("root");// 设置初始化连接数量dataSource.setInitialPoolSize(5);// 3.获得连接Connection connection = dataSource.getConnection();// 4.书写sql语句,预编译sql语句,得到预编译对象String sql = "select * from user where id = ?";PreparedStatement ps = connection.prepareStatement(sql);// 5.设置参数ps.setInt(1, 3);// 6.执行sql语句ResultSet resultSet = ps.executeQuery();// 封装,处理数据User user = null;while (resultSet.next()) {user = new User();user.setId(resultSet.getInt("id"));user.setUsername(resultSet.getString("username"));user.setPassword(resultSet.getString("password"));user.setNickname(resultSet.getString("nickname"));}System.out.println(user);// 7.释放资源---连接归还JDBCUtils.release(resultSet,ps,connection);}
}

2.2.2.2 通过配置文件来编写

步骤:

  1. 拷贝jar
  2. 拷贝配置文件(c3p0-config.xml)到src目录【名字不要改
  3. 创建C3P0连接池对象【自动的读取】
  4. 从池子里面获得连接

实现:

  • 编写配置文件c3p0-config.xml,放在src目录下(注:文件名一定不要改)
<c3p0-config><default-config><property name="driverClass">com.mysql.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://localhost:3306/hashnode</property><property name="user">root</property><property name="password">root</property><property name="initialPoolSize">5</property></default-config>
</c3p0-config>
  • 编写Java代码 (会自动读取src目录下的c3p0-config.xml,所以不需要我们解析配置文件)
public class Test2_通过配置文件来编写 {public static void main(String[] args) throws Exception{// 1.拷贝c3p0jar包到模块下,并添加到classpath路径中// 2.创建连接池对象ComboPooledDataSource dataSource = new ComboPooledDataSource();// 3.获得连接Connection connection = dataSource.getConnection();// 4.书写sql语句,预编译sql语句,得到预编译对象String sql = "select * from user where id = ?";PreparedStatement ps = connection.prepareStatement(sql);// 5.设置参数ps.setInt(1, 3);// 6.执行sql语句ResultSet resultSet = ps.executeQuery();// 封装,处理数据User user = null;while (resultSet.next()) {user = new User();user.setId(resultSet.getInt("id"));user.setUsername(resultSet.getString("username"));user.setPassword(resultSet.getString("password"));user.setNickname(resultSet.getString("nickname"));}System.out.println(user);// 7.释放资源---连接归还JDBCUtils.release(resultSet,ps,connection);}
}

2.2.2.3 使用c3p0改写工具类

​ 我们之前写的工具类(JdbcUtils)每次都会创建一个新的连接, 使用完成之后, 都给销毁了; 所以现在我们要使用c3p0来改写工具类. 也就意味着,我们从此告别了JdbcUtils. 后面会使用c3p0写的工具类

思路:

  1. 创建C3P0Utils这个类
  2. 定义DataSource, 保证DataSource全局只有一个
  3. 定义getConnection()方法从DataSource获得连接
  4. 定义closeAll()方法 释放资源
package com.hashnode.utils;import com.mchange.v2.c3p0.ComboPooledDataSource;import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;public class C3P0Utils {// 创建c3p0连接池对象private static final ComboPooledDataSource DATA_SOURCE = new ComboPooledDataSource();/*** 获得连接的方法* @return  连接* @throws Exception*/public static Connection getConnection() throws Exception{Connection connection = DATA_SOURCE.getConnection();return connection;}/*** 获得连接池的方法* @return*/public static DataSource getDataSource(){return DATA_SOURCE;}/*** 释放资源** @param resultSet* @param statement* @param connection*/public static void release(ResultSet resultSet, Statement statement, Connection connection) {if (resultSet != null) {try {resultSet.close();} catch (SQLException e) {e.printStackTrace();}}if (statement != null) {try {statement.close();} catch (SQLException e) {e.printStackTrace();}}if (connection != null) {try {connection.close();} catch (SQLException e) {e.printStackTrace();}}}
}
  • 使用
package com.hashnode.test;import com.hashnode.pojo.User;
import com.hashnode.utils.JDBCUtils;
import com.mchange.v2.c3p0.ComboPooledDataSource;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;public class C3P0Test2 {public static void main(String[] args) throws Exception{// 1.拷贝c3p0jar包到模块下,并添加到classpath路径中// 2.创建连接池对象ComboPooledDataSource dataSource = new ComboPooledDataSource();// 3.获得连接Connection connection = dataSource.getConnection();// 4.书写sql语句,预编译sql语句,得到预编译对象String sql = "select * from user where id = ?";PreparedStatement ps = connection.prepareStatement(sql);// 5.设置参数ps.setInt(1, 3);// 6.执行sql语句ResultSet resultSet = ps.executeQuery();// 封装,处理数据User user = null;while (resultSet.next()) {user = new User();user.setId(resultSet.getInt("id"));user.setUsername(resultSet.getString("username"));user.setPassword(resultSet.getString("password"));user.setNickname(resultSet.getString("nickname"));}System.out.println(user);// 7.释放资源---连接归还JDBCUtils.release(resultSet,ps,connection);}
}

小结

  1. C3P0 配置文件方式使用

    • 拷贝jar
    • 拷贝配置文件到src【配置文件的名字不要改】
    • 创建C3P0连接池对象
  2. C3P0工具类

    • 保证DataSource连接池只有一个【static】
    • 提供connection
    • 释放资源

2.3 DRUID

2.3.1 DRUID介绍

​ Druid是阿里巴巴开发的号称为监控而生的数据库连接池,Druid是国内目前最好的数据库连接池。在功能、性能、扩展性方面,都超过其他数据库连接池。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。如:一年一度的双十一活动,每年春运的抢火车票。

Druid的下载地址:https://github.com/alibaba/druid

DRUID连接池使用的jar包:druid-1.0.9.jar

2.3.2 DRUID的使用

2.3.3 通过硬编码方式

步骤:

  1. 导入DRUID jar 包
  2. 创建Druid连接池对象, 配置4个基本参数
  3. 从Druid连接池对象获得Connection

实现:

package com.hashnode.test;import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection;
import com.hashnode.pojo.User;
import com.hashnode.utils.JDBCUtils;
import org.junit.Test;import java.sql.PreparedStatement;
import java.sql.ResultSet;public class DruidTest1 {@Testpublic void select() throws Exception{// 1.拷贝jar包,添加classpath路径// 2.创建Druid连接池对象DruidDataSource dataSource = new DruidDataSource();// 设置参数dataSource.setDriverClassName("com.mysql.jdbc.Driver");dataSource.setUrl("jdbc:mysql://localhost:3306/hashnode");dataSource.setUsername("root");dataSource.setPassword("root");dataSource.setInitialSize(5);// 3.获得连接DruidPooledConnection connection = dataSource.getConnection();// 4.书写sql语句,预编译sql语句,得到预编译对象String sql = "select * from user where id = ?";PreparedStatement ps = connection.prepareStatement(sql);// 5.设置参数ps.setInt(1, 3);// 6.执行sql语句ResultSet resultSet = ps.executeQuery();// 封装,处理数据User user = null;while (resultSet.next()) {user = new User();user.setId(resultSet.getInt("id"));user.setUsername(resultSet.getString("username"));user.setPassword(resultSet.getString("password"));user.setNickname(resultSet.getString("nickname"));}System.out.println(user);// 7.释放资源---连接归还JDBCUtils.release(resultSet,ps,connection);}
}

2.3.4 通过配置文件方式

步骤:

  1. 导入DRUID jar 包
  2. 拷贝配置文件到src目录
  3. 根据配置文件创建Druid连接池对象
  4. 从Druid连接池对象获得Connection

实现:

  • 创建druid.properties, 放在src目录下
url=jdbc:mysql://localhost:3306/day21_1
username=root
password=root
driverClassName=com.mysql.jdbc.Driver
  • 编写Java代码
package com.hashnode.test;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.hashnode.pojo.User;
import com.hashnode.utils.JDBCUtils;
import org.junit.Test;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;public class DruidTest2 {@Testpublic void select() throws Exception{// 1.拷贝jar包,添加classpath路径// 2.创建Druid连接池对象Properties prop = new Properties();// 加载配置文件InputStream is = DruidTest2.class.getClassLoader().getResourceAsStream("druid.properties");prop.load(is);// 创建Druid连接池对象DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);// 3.获得连接Connection connection = dataSource.getConnection();// 4.书写sql语句,预编译sql语句,得到预编译对象String sql = "select * from user where id = ?";PreparedStatement ps = connection.prepareStatement(sql);// 5.设置参数ps.setInt(1, 3);// 6.执行sql语句ResultSet resultSet = ps.executeQuery();// 封装,处理数据User user = null;while (resultSet.next()) {user = new User();user.setId(resultSet.getInt("id"));user.setUsername(resultSet.getString("username"));user.setPassword(resultSet.getString("password"));user.setNickname(resultSet.getString("nickname"));}System.out.println(user);// 7.释放资源---连接归还JDBCUtils.release(resultSet,ps,connection);}
}

2.3.5 使用DruidUtils改写工具类

思路:

  1. 创建DruidUtils这个类
  2. 定义DruidDataSource, 保证DruidDataSource全局只有一个
  3. 定义getConnection()方法从DataSource获得连接
  4. 定义release()方法 释放资源
package com.hashnode.utils;import com.alibaba.druid.pool.DruidDataSource;import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;public class DruidUtils {// 创建c3p0连接池对象private static final DruidDataSource DATA_SOURCE = new DruidDataSource();static {// 设置参数DATA_SOURCE.setDriverClassName("com.mysql.jdbc.Driver");DATA_SOURCE.setUrl("jdbc:mysql://localhost:3306/hashnode");DATA_SOURCE.setUsername("root");DATA_SOURCE.setPassword("root");DATA_SOURCE.setInitialSize(5);}/*** 获得连接的方法* @return  连接* @throws Exception*/public static Connection getConnection() throws Exception{Connection connection = DATA_SOURCE.getConnection();return connection;}/*** 获得连接池的方法* @return*/public static DruidDataSource getDataSource(){return DATA_SOURCE;}/*** 释放资源** @param resultSet* @param statement* @param connection*/public static void release(ResultSet resultSet, Statement statement, Connection connection) {if (resultSet != null) {try {resultSet.close();} catch (SQLException e) {e.printStackTrace();}}if (statement != null) {try {statement.close();} catch (SQLException e) {e.printStackTrace();}}if (connection != null) {try {connection.close();} catch (SQLException e) {e.printStackTrace();}}}
}
  • 使用
package com.hashnode.test;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.hashnode.pojo.User;
import com.hashnode.utils.DruidUtils;
import com.hashnode.utils.JDBCUtils;
import org.junit.Test;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;public class DruidTest3 {@Testpublic void select() throws Exception{// 3.获得连接Connection connection = DruidUtils.getConnection();// 4.书写sql语句,预编译sql语句,得到预编译对象String sql = "select * from user where id = ?";PreparedStatement ps = connection.prepareStatement(sql);// 5.设置参数ps.setInt(1, 3);// 6.执行sql语句ResultSet resultSet = ps.executeQuery();// 封装,处理数据User user = null;while (resultSet.next()) {user = new User();user.setId(resultSet.getInt("id"));user.setUsername(resultSet.getString("username"));user.setPassword(resultSet.getString("password"));user.setNickname(resultSet.getString("nickname"));}System.out.println(user);// 7.释放资源---连接归还DruidUtils.release(resultSet,ps,connection);}
}

小结

  1. Druid配置文件使用

    • 拷贝jar
    • 拷贝配置文件到src
    • 读取配置文件成properties对象
    • 使用工厂根据properties创建DataSource
    • 从DataSource获得Connection

【MySQL】数据库连接池的原理及实现相关推荐

  1. Node.js实现MySQL数据库连接池

    Node.js实现MySQL数据库连接池 1 什么是数据库连接池 2 原理及优点 3 连接池的作用 4 实现连接池 4.1 导入mysql模块 4.2 创建数据库连接池 4.3 从连接池中获取一个连接 ...

  2. Tomcat 5.5 配置 MySQL 数据库连接池

    用了最新的几个咚咚,搞了整整一天终于搞清楚了Tomcat 5.5 配置 MySQL 数据库连接池,网上的经验并不能完全用到新环境里面,我写出整个过程以方便大家配置. 1 环境描述 JDK 1.5 To ...

  3. python实现数据库连接池_Python实现Mysql数据库连接池

    Python实现Mysql数据库连接池 python连接Mysql数据库: python编程中可以使用MySQLdb进行数据库的连接及诸如查询/插入/更新等操作,但是每次连接mysql数据库请求时,都 ...

  4. tomcat7.0.42如何设置mysql数据库连接池

    转载自   tomcat7.0.42如何设置mysql数据库连接池 如何在tomcat7.0.42中设置mysql数据库连接池????eclipse如何绑定tomcat??按网上教程总不成功!怎么办 ...

  5. jboss mysql cluster_jboss配置mysql数据库连接池

    jboss配置mysql数据库连接池 下面YJBYS小编为大家整理了关于jboss配置mysql数据库连接池的文章,希望对你有所帮助.更多Java认证考试信息,尽在应届毕业生培训网! 1:配置: JD ...

  6. 面试官:谈谈数据库连接池的原理

    来源:https://dwz.cn/oUF6pKOW 这次我们采取技术演进的方式来谈谈数据库连接池的技术出现过程及其原理,以及当下最流行的开源数据库连接池jar包. 一.早期我们怎么进行数据库操作 1 ...

  7. 3 连接sybase_今日头条面试官:给我说说数据库连接池的原理?

    作者:敦格 来源:https://urlify.cn/ABJbum 这次我们采取技术演进的方式来谈谈数据库连接池的技术出现过程及其原理,以及当下最流行的开源数据库连接池jar包. # 早期我们怎么进行 ...

  8. Python操作数据库及Python实现mysql数据库连接池源代码

    简介 pymysql:纯Python实现的一个驱动.因为是纯Python编写的,因此执行效率不如MySQL-python.并且也因为是纯Python编写的,因此可以和Python代码无缝衔接. MyS ...

  9. 谈谈数据库连接池的原理

    这次我们采取技术演进的方式来谈谈数据库连接池的技术出现过程及其原理,以及当下最流行的开源数据库连接池jar包. 一.早期我们怎么进行数据库操作        1.原理:一般来说,java应用程序访问数 ...

最新文章

  1. DeepFake噩梦来了!武大阿里团队提出FakeTagger,重新识别率达95%
  2. mysql 同步备份数据库
  3. linux如何查看jupyter日志_Mac如何远程连接上Linux下的jupyter notebook
  4. html 图片 保持长宽比,实现图片在页面中宽高一直保持16:9比例的方法
  5. 实验4 数据查询--简单查询
  6. 深入理解SQL Server的规划和安装
  7. 股票价格跨度--单调栈
  8. js return 闭包为null_js 基础知识总结
  9. 条件编译宏定义_C语言学习- 预处理指令2 - 条件编译
  10. 使用Canvas绘制简单工程符号
  11. 世界著名大学校训(中英文版)
  12. 幼麟棋牌游戏进程分析
  13. python编程题13-蒙特·卡罗方法计算圆周率
  14. 蓝奏云打不开的解决方法
  15. 按键式计算器——人机交互的变革
  16. jsp对象的四大作用域的简单介绍
  17. 2020浙江大学软件学院预推免经验
  18. 服务器怎么显示我的电脑图标没了,我的电脑图标没了怎么办?在这里可以将它显示出来...
  19. 《中国移动交通强国建设试点实施方案》获批!
  20. 请教关于Cisco ap1242的web配置

热门文章

  1. slice与splice用法
  2. java 上传图片与图片读取
  3. c++:dll缺少依赖文件的解决方法
  4. rebar3简单使用
  5. 查看 Windows 10 快捷键 占用 VSCode 多行编辑 ctrl alt uparrow
  6. 移动电信数据仓库设计六环节
  7. 数据库CAST()函数,格式(CAST AS decimal)
  8. 生成式模型与辨别式模型
  9. MATLAB矩阵的建立
  10. 【入门】1536- 前端 Flutter 入门指南