資料庫連線池的簡單實現
阿新 • • 發佈:2019-02-09
> 資料庫連線池負責分配、管理和釋放資料庫連線,它允許應用程式重複使用一個現有的資料庫連線,而不是再重新建立一個;釋放空閒時間超過最大空閒時間的資料庫連線來避免因為沒有釋放資料庫連線而引起的資料庫連線遺漏。這項技術能明顯提高對資料庫操作的效能。
一、定義連線池介面IPool
package jdbcPool;
public interface IPool {
/**
* 從池中獲取連線
* @return
*/
PooledConnection getConnection();
/**
* 建立連線到池中
* @param count 建立數量
*/
void createConnections(int count);
}
二、封裝連線Connection的類PooledConnection
package jdbcPool;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class PooledConnection {
//jdbc連線
private Connection connection;
//連線是否被佔用
private boolean isBusy;
public PooledConnection(Connection connection, boolean isBusy) {
this.connection = connection;
this.isBusy = isBusy;
}
public Connection getConnection() {
return connection;
}
public void setConnection(Connection connection) {
this .connection = connection;
}
public boolean isBusy() {
return isBusy;
}
public void setBusy(boolean isBusy) {
this.isBusy = isBusy;
}
public ResultSet queryBySql(String sql) throws SQLException, InterruptedException {
Statement sm = null;
ResultSet rs = null;
try {
sm = connection.createStatement();
rs = sm.executeQuery(sql);
}
catch (SQLException e) {
e.printStackTrace();
}
return rs;
}
//釋放連線
public void close() {
isBusy = false;
}
}
二、實現IPool介面JdbcPool
package jdbcPool;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
import java.util.Vector;
public class JdbcPool implements IPool {
//jdbc驅動
private String jdbcDriver = "";
//jdbc連線url
private String dbUrl = "";
//使用者名稱
private String dbUsername = "";
//密碼
private String dbPassword = "";
//初始化大小
private int initConnCount;
//最大連線數
private int maxConnects;
//每次增長大小
private int incrementalCount;
//連線集合
private static Vector<PooledConnection> pool = new Vector<PooledConnection>();
//初始化連線池
public void init() {
InputStream is = JdbcPool.class.getClassLoader().getResourceAsStream("jdbcPool/jdbc.properties");
Properties p = new Properties();
try {
p.load(is);
} catch (IOException e) {
e.printStackTrace();
}
jdbcDriver = p.getProperty("jdbcDriver");
dbUrl = p.getProperty("dbUrl");
dbUsername = p.getProperty("dbUsername");
dbPassword = p.getProperty("dbPassword");
initConnCount = Integer.valueOf(p.getProperty("initConnCount"));
maxConnects = Integer.valueOf(p.getProperty("maxConnnects"));
incrementalCount = Integer.valueOf(p.getProperty("incrementalcount"));
try {
Class.forName(jdbcDriver);
createConnections(initConnCount);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public void createConnections(int count) {
System.out.println("執行緒名:" + Thread.currentThread().getName() + "建立了"+count+"個連線");
for (int i = 0; i < count; i++) {
//我們建立連線的時候,必須要判斷這個池中的連線要小於我們的最大連線
if (maxConnects > 0 && pool.size() >= maxConnects) {
System.out.println("連線池中的連線數量已經達到了最大值!");
return;
}
try {
Connection connection = DriverManager.getConnection(dbUrl, dbUsername, dbPassword);
pool.add(new PooledConnection(connection, false));
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public PooledConnection getActiveConnection() {
for (PooledConnection conn : pool) {
if (!conn.isBusy()) {
Connection trueconn = conn.getConnection();
try {
if (!trueconn.isValid(0)) {//連線是否有效
Connection newconn = DriverManager.getConnection(dbUrl,
dbUsername,
dbPassword);
conn.setConnection(newconn);
}
}
catch (SQLException e) {
e.printStackTrace();
}
conn.setBusy(true);
return conn;
}
}
return null;
}
@Override
public synchronized PooledConnection getConnection() {
if (pool.size() <= 0) {
System.out.println("連線池中還沒有連線!");
throw new RuntimeException("連線池中還沒有連線!");
}
PooledConnection conn = getActiveConnection();
if(null == conn){
System.out.println("連線池中中已連線用完");
createConnections(incrementalCount);
conn = getActiveConnection();
while (conn == null) {
try {
Thread.sleep(300);
}
catch (InterruptedException e) {
e.printStackTrace();
}
conn = getActiveConnection();
}
}
return conn;
}
public static Vector<PooledConnection> getPool() {
return pool;
}
}
四、連線池管理DBManager
package jdbcPool;
public class DBManager {
private static class CreatePool {
private static JdbcPool pool = new JdbcPool();
}
public static JdbcPool getInstance(){
return CreatePool.pool;
}
}
五、測試連線池
package jdbcPool;
import java.sql.ResultSet;
import java.util.concurrent.CountDownLatch;
import org.junit.Before;
import org.junit.Test;
public class JdbcPoolTest {
private int threadCount = 1000;
private CountDownLatch latch = new CountDownLatch(threadCount);
JdbcPool pool = DBManager.getInstance();
@Before
public void before() {
pool.init();
}
public void select() throws Exception {
PooledConnection conn = pool.getConnection();
ResultSet rs = conn.queryBySql("select * from tbl_user");
if (rs.next()) {
System.out.println("執行緒名:" + Thread.currentThread().getName() + "====="+ rs.getString("account") );
}
rs.close();
conn.close();
}
@Test
public void threadTest() throws InterruptedException {
for (int i = 0; i < threadCount; i++) {
new Thread(new Runnable() {
public void run() {
try {
latch.await();
select();
}
catch (Exception e) {
e.printStackTrace();
}
}
}).start();
latch.countDown();
}
Thread.sleep(3000);
System.out.println(JdbcPool.getPool().size());
}
}
測試效果
執行緒名:main建立了10個連線
執行緒名:Thread-57=====PN135998
連線池中中已連線用完
執行緒名:Thread-98建立了2個連線
連線池中中已連線用完
執行緒名:Thread-49建立了2個連線
執行緒名:Thread-53=====PN135998
執行緒名:Thread-52=====PN135998
執行緒名:Thread-999=====PN135998
執行緒名:Thread-55=====PN135998
執行緒名:Thread-51=====PN135998
執行緒名:Thread-88=====PN135998
執行緒名:Thread-56=====PN135998
執行緒名:Thread-50=====PN135998
…….
14