第三章 数据库连接池
1.1 概述
我们需要一个容器,来提前保存连接对象,而这个东西就叫做数据库线程池
数据库连接池: 其实就是一个容器(集合),存放数据库连接的容器
当系统初始化好之后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库的时候,从容器中获取连接对象;用户访问完之后,就将连接对象归还;
优点
- 节约资源
- 用户访问高效(如果自己getConnection的话就要对底层获取资源,比较没有效率)
注意:
数据库连接池的实现,使用标准接口:DataSource (在javax.sql包下)
1.方法:
①获取连接:getConnection()
②归还连接:Connection.close()
2.一般我们不去实现它,有数据库厂商来实现:Druid
基本实现
使用标准接口javax.sql.DataSource(接口的实现类由数据库的厂商提供),对于DriverManager设备的替代方案,这个接口是获取连接的首选方法
方法:
//获取连接
Connection getConnection() //尝试建立与此 DataSource对象所代表的数据源的连接。
Connection getConnection(String username, String password) //尝试建立与此 DataSource对象所代表的数据源的连接。
//归还连接:如果连接对象是从连接池中获取,那么调用Connection.close()方法,就不会再关闭连接,而是归还连接
connecion.close();
几种常用的数据库连接池技术
C3P0: 比较老
Druid(德鲁伊): 比较新的数据库连接池实现技术,由阿里巴巴提供的,非常高效,号称全世界最好的数据库连接池技术之一
1.2 C3P0技术
使用步骤:
-
导入jar包: c3p0-0.9.5.5-sources.jar 和 mchange-commons-java-0.2.19-sources.jar (注意,数据库的jar包也记得要导mysql-connector-java-8.0.13-bin.jar)
-
定义配置文件
名称:c3p0.peoperties 或者 c3p0-config.xml
路径: src源目录文件下 自动配置,无需手动
-
创建核心对象: 数据库连接池对象: new ComboPooledDataSource()
-
获取连接: getConnection()
配置文件
<c3p0-config>
<!-- 使用默认的配置读取连接池对象 -->
<default-config>
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/javademo</property>
<property name="user">root</property>
<property name="password">bpqbfq769</property>
<!-- 连接池参数 -->
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">10</property>
<property name="checkoutTimeout">3000</property>
</default-config>
<named-config name="otherc3p0">
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/javademo</property>
<property name="user">root</property>
<property name="password">123456</property>
<!-- 连接池参数 -->
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">8</property>
<property name="checkoutTimeout">1000</property>
</named-config>
</c3p0-config>
例子:
public static void main(String[] args) throws SQLException {
//1.创建数据库连接池对象 使用默认配置
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
//不使用默认配置
// ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("otherc3p0");
//2.获取连接对象,可以在配置文件中设定连接池中最大数量
for (int i = 0; i <=10 ; i++) {
Connection connection = comboPooledDataSource.getConnection();
System.out.println(i+":"+connection);
}
}
1.3 Druid技术
使用步骤
- 导入jar包( mysql-connector-java-8.0.13-bin.jar和druid-1.0.9.jar)
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.13</version>
</dependency>
<!--druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
- 定义配置文件:(.peoperties形式的)
可为任意名称,可以放在任意目录下,需手动读取这个配置文件 - 加载配置文件:properties
- 获取数据库连接池对象: 通过工厂类 DruidDataSourceFactory
- 获取连接: getConnection()
配置文件
url = jdbc:mysql:///door?serverTimezone=GMT%2B8
username = root
password = bpqbfq769
initialSize = 5 //初始化连接数
maxActive = 10 //最大连接数
maxWait = 3000 //最大等待时间
//再添加一些
filters=stat
// 初始化连接数量
initialSize=6
// 最大连接数
maxActive=10
// 最大等待时间
maxWait=3000
// 每30秒运行一次空闲连接回收器
timeBetweenEvictionRunsMillis=30000
// 池中的连接空闲30分钟后被回收,默认值就是30分钟。
minEvictableIdleTimeMillis=1800000
// 验证连接是否可用,使用的SQL语句
validationQuery=SELECT 1
// 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除.
testWhileIdle=true
// 借出连接时不要测试,否则很影响性能
testOnBorrow=false
testOnReturn=false
poolPreparedStatements=false
maxPoolPreparedStatementPerConnectionSize=200
例子:
public static void main(String[] args) throws Exception {
//1.导入jar包
//2.定义配置文件
//3.加载配置文件
Properties pro = new Properties();
InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
//4.获取连接池对象
DataSource ds = DruidDataSourceFactory.createDataSource(pro);
//5.获取连接
Connection conn = ds.getConnection();
System.out.println(conn);
}
小试牛刀
import com.alibaba.druid.pool.DruidDataSourceFactory;
import demo12.util.JDBCUtils;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;
public class DataSource {
public static void main(String[] args) throws Exception {
//1.手动配置加载文件
ClassLoader cll = DataSource.class.getClassLoader();
InputStream rs = cll.getResourceAsStream("druid.properties");
pro.load(rs);
//2.创建连接对象,这里参数要一个Properties
javax.sql.DataSource dataSource = DruidDataSourceFactory.createDataSource(pro);
//3.获取数据库连接对象
Connection conn = dataSource.getConnection();
//4.获取执行sql的对象Statement
Statement stmt = conn.createStatement();
//5.定义sql语句
String sql = "select * from buyer";
// 6.执行sql
ResultSet res = stmt.executeQuery(sql);
//7. 处理结果
while (res.next()){
System.out.println(res.getInt(1) + " \t" + res.getString(2) + "\t" + res.getDouble(3));
}
//8. 释放资源
JDBCUtils.close(stmt,conn);
//或 8.释放资源
//statement.close();
//con.close();
}
}
//处理结果
4月 22, 2021 11:39:13 上午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
1 zhangsan 2000.0
2 lisi 6000.0
1.4 Druid工具类
我们发现这个过程还是有点麻烦,所以我们打算通过自己写一个改良版的工具类来简化这个过程.
步骤
-
定义一个工具类JDBCUtils
-
提供静态代码块加载配置文件,同时初始化连接池对象
-
提供方法:
获取连接对象,
释放资源
获取连接池对象的方法
工具类
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* JDBC工具类
*/
public class JDBCDruidUtils {
//1.定义成员变量 DataSource
private static final Properties pro;
private static DataSource dataSource;
//配置文件的读取,只需要一次就可以了,用静态代码块
static {
//手动加载配置文件
pro = new Properties();
ClassLoader cl = JDBCDruidUtils.class.getClassLoader();
InputStream is = cl.getResourceAsStream("druid.properties");
try {
pro.load(is);
} catch (IOException e) {
e.printStackTrace();
}
//初始化连接池对象
try {
dataSource = DruidDataSourceFactory.createDataSource(pro);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接对象
public static Connection getConnection() throws Exception {
return dataSource.getConnection();
}
//关闭资源
public static void close(Statement stmt, Connection conn) {
judge(stmt, conn);
}
public static void judge(Statement stmt, Connection conn) {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
//获取连接池的方法
public static DataSource getDataSource(){
return dataSource;
}
}
代码测试1
import demo12.util.JDBCDruidUtils;
import demo12.util.JDBCUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
public class DataSource {
public static void main(String[] args) throws Exception {
Connection conn = JDBCDruidUtils.getConnection();
Statement stmt = conn.createStatement();
String sql = "select * from account";
// 执行sql
ResultSet res = stmt.executeQuery(sql);
//7 处理结果
while (res.next()){
System.out.println(res.getInt(1) + " \t" + res.getString(2) + "\t" + res.getDouble(3));
}
//8 释放资源
JDBCUtils.close(stmt,conn);
}
}
//运行结果
4月 22, 2021 12:38:17 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
1 zhangsan 2000.0
2 lisi 6000.0
代码测试2
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt = null;
try {
//1.获取连接
conn = JDBCutils.getConnection();
//2.定义sql
String sql = "insert into student3 values(null,?,?,?,?,?,?)";
//3.获取执行sql语句的对象
pstmt = conn.prepareStatement(sql);
//4.给?赋值
pstmt.setString(1,"小白龙");
pstmt.setInt(2,19);
pstmt.setString(3,"男");
pstmt.setString(4,"大唐");
pstmt.setInt(5,66);
pstmt.setInt(6,99);
//5.执行sql
int count = pstmt.executeUpdate();
System.out.println(count);
} catch (SQLException e) {
e.printStackTrace();
} finally {
//6.释放资源
JDBCutils.close(pstmt,conn);
}
}