Java自学-JDBC 数据库连接池
数据库连接池
与线程池类似的,数据库也有一个数据库连接池。 不过他们的实现思路是不一样的。
本章节讲解了自定义数据库连接池类:ConnectionPool,虽然不是很完善和健壮,但是足以帮助大家理解 ConnectionPool 的基本原理。
步骤 1 : 数据库连接池原理 - 传统方式
当有多个线程,每个线程都需要连接数据库执行 SQL 语句的话,那么每个线程都会创建一个连接,并且在使用完毕后,关闭连接。
创建连接和关闭连接的过程也是比较消耗时间的,当多线程并发的时候,系统就会变得很卡顿。
同时,一个数据库同时支持的连接总数也是有限的,如果多线程并发量很大,那么数据库连接的总数就会被消耗光,后续线程发起的数据库连接就会失败。
步骤 2 : 数据库连接池原理 - 使用池
与传统方式不同,连接池在使用之前,就会创建好一定数量的连接。
如果有任何线程需要使用连接,那么就从连接池里面借用,而不是自己重新创建.
使用完毕后,又把这个连接归还给连接池供下一次或者其他线程使用。
倘若发生多线程并发情况,连接池里的连接被借用光了,那么其他线程就会临时等待,直到有连接被归还回来,再继续使用。
整个过程,这些连接都不会被关闭,而是不断的被循环使用,从而节约了启动和关闭连接的时间。
步骤 3 : ConnectionPool 构造方法和初始化
-
ConnectionPool() 构造方法约定了这个连接池一共有多少连接
-
在 init() 初始化方法中,创建了 size 条连接。 注意,这里不能使用 try-with-resource 这种自动关闭连接的方式,因为连接恰恰需要保持不关闭状态,供后续循环使用
-
getConnection, 判断是否为空,如果是空的就 wait 等待,否则就借用一条连接出去
-
returnConnection, 在使用完毕后,归还这个连接到连接池,并且在归还完毕后,调用 notifyAll,通知那些等待的线程,有新的连接可以借用了。
注:连接池设计用到了多线程的 wait 和 notifyAll
package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class ConnectionPool {
List<Connection> cs = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span><Connection>();
<span class="hljs-type">int</span> size;
<span class="hljs-keyword">public</span> <span class="hljs-title function_">ConnectionPool</span><span class="hljs-params">(<span class="hljs-type">int</span> size)</span> {
<span class="hljs-built_in">this</span>.size = size;
init();
}
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">init</span><span class="hljs-params">()</span> {
<span class="hljs-comment">//这里恰恰不能使用try-with-resource的方式,因为这些连接都需要是"活"的,不要被自动关闭了</span>
<span class="hljs-keyword">try</span> {
Class.forName(<span class="hljs-string">"com.mysql.jdbc.Driver"</span>);
<span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> <span class="hljs-variable">i</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; i < size; i++) {
<span class="hljs-type">Connection</span> <span class="hljs-variable">c</span> <span class="hljs-operator">=</span> DriverManager
.getConnection(<span class="hljs-string">"jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8"</span>, <span class="hljs-string">"root"</span>, <span class="hljs-string">"admin"</span>);
cs.add(c);
}
} <span class="hljs-keyword">catch</span> (ClassNotFoundException e) {
<span class="hljs-comment">// TODO Auto-generated catch block</span>
e.printStackTrace();
} <span class="hljs-keyword">catch</span> (SQLException e) {
<span class="hljs-comment">// TODO Auto-generated catch block</span>
e.printStackTrace();
}
}
<span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> Connection <span class="hljs-title function_">getConnection</span><span class="hljs-params">()</span> {
<span class="hljs-keyword">while</span> (cs.isEmpty()) {
<span class="hljs-keyword">try</span> {
<span class="hljs-built_in">this</span>.wait();
} <span class="hljs-keyword">catch</span> (InterruptedException e) {
<span class="hljs-comment">// TODO Auto-generated catch block</span>
e.printStackTrace();
}
}
<span class="hljs-type">Connection</span> <span class="hljs-variable">c</span> <span class="hljs-operator">=</span> cs.remove(<span class="hljs-number">0</span>);
<span class="hljs-keyword">return</span> c;
}
<span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">returnConnection</span><span class="hljs-params">(Connection c)</span> {
cs.add(c);
<span class="hljs-built_in">this</span>.notifyAll();
}
}
步骤 4 : 测试类
首先初始化一个有 3 条连接的数据库连接池
然后创建 100 个线程,每个线程都会从连接池中借用连接,并且在借用之后,归还连接。 拿到连接之后,执行一个耗时 1 秒的 SQL 语句。
运行程序,就可以观察到如图所示的效果
package jdbc;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import jdbc.ConnectionPool;
public class TestConnectionPool {
<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> {
<span class="hljs-type">ConnectionPool</span> <span class="hljs-variable">cp</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ConnectionPool</span>(<span class="hljs-number">3</span>);
<span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> <span class="hljs-variable">i</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; i < <span class="hljs-number">100</span>; i++) {
<span class="hljs-keyword">new</span> <span class="hljs-title class_">WorkingThread</span>(<span class="hljs-string">"working thread"</span> + i, cp).start();
}
}
}
class WorkingThread extends Thread {
private ConnectionPool cp;
<span class="hljs-keyword">public</span> <span class="hljs-title function_">WorkingThread</span><span class="hljs-params">(String name, ConnectionPool cp)</span> {
<span class="hljs-built_in">super</span>(name);
<span class="hljs-built_in">this</span>.cp = cp;
}
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">run</span><span class="hljs-params">()</span> {
<span class="hljs-type">Connection</span> <span class="hljs-variable">c</span> <span class="hljs-operator">=</span> cp.getConnection();
System.out.println(<span class="hljs-built_in">this</span>.getName()+ <span class="hljs-string">":\t 获取了一根连接,并开始工作"</span> );
<span class="hljs-keyword">try</span> (<span class="hljs-type">Statement</span> <span class="hljs-variable">st</span> <span class="hljs-operator">=</span> c.createStatement()){
<span class="hljs-comment">//模拟时耗1秒的数据库SQL语句</span>
Thread.sleep(<span class="hljs-number">1000</span>);
st.execute(<span class="hljs-string">"select * from hero"</span>);
} <span class="hljs-keyword">catch</span> (SQLException | InterruptedException e) {
<span class="hljs-comment">// TODO Auto-generated catch block</span>
e.printStackTrace();
}
cp.returnConnection(c);
}
}
更多内容,点击了解: JDBC 数据库连接池