JDBC連接數據庫及其連接池

之所有要寫這麼一個數據庫連接方法,就是爲了有一個整理一下思路和所需要的東西總是會丟三落四,總是不好找,所以整理好,總不至於在需要的東西總是找不到。

一:JDBC連接數據庫:

首先,連接數據庫的準備工作:

1.我所用的編寫工具爲eclipse和Navicat。

2.連接數據庫要有所需要的jar包。

 

自定義連接只需要jar包爲驅動包Mysql—connector-java-xxx-bin.jar

在連接中所需要的類有Connection類、ResultSet類、Statement類。

那麼究竟怎樣才能連接到數據庫,並且能在界面化上才做數據呢?要想完成這樣的操作,首先我們要得和Navicat獲取連接。我們要加載連接數據庫的驅動。也就是上面所需要的jar包驅動,把它放在eclipse中新建的工程的lib裏面,在build Path一下,使用Class.forName(“com.mysql.jdbc.Driver”)來註冊驅動。這就完成了對驅動的註冊,之後獲取數據庫的連接,使用Manager.getConnection(url,username,password),url="jdbc:mysql://127.0.0.1/3306/表名?useUnicoding=true&characterEncoding=utf8",username="連接數據庫的名稱",password="連接數據庫的密碼";這樣就已經連接上了數據庫。

那麼接下來我們就對數據庫進行操作:

我們知道,對數據庫的操作‘無非就是對數據庫的增刪改查,我們寫出相應的增刪改查的sql語句。

增:insert into 表名(firstName,secondName,thirdName,fourthName) values(?,?,?,?);

刪:delet frome 表的名稱 where 條件;

改:updata 表名 set 字段="需要改的值" where ID="條件";

查:select * from 表名;查詢所有的值;

寫出相應的SQL語句,並且創建出Statement對象;connection.excuteQuery(sql);這樣查詢相應的數據。connction.executUpdate(sql);來執行相應的增刪改;

使用Statement類我們需要注意一個問題,那就是會出現sql注入問題,所以一般我們會使用PrepareStatement類,所以在使用的時候,創建出所使用的PrepareStatement類,使用PrepareStatement類的excuteQuery(sql)來執行查詢,excuteUpdata(sql)來更新。當然,我們都是在執行sql語句,但是對於Connection類、Statement類、ResultSet類、PrepareStatement類我們需要把它們關掉,不然會浪費資源。判斷是否存在,若是存在,那麼就.Close()關掉。

 

回到我們的標題,自定義連接,但是我們在執行不論是增刪改查存在重複的相同的代碼,我們是否可以對應的封裝一下,封裝成相應的工具類。那麼以後我們就可以使用對應的工具類了,不用這麼麻煩的寫重複的代碼。而且我們若是在源代碼中去改連接數據庫的表名、用戶名、密碼是不是很麻煩呢?有沒有什麼方法方便去修改這些經常去改變的東西呢?

我們可以使用外部文件去修改:

外部文件:文件名固定爲:xxx.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/數據庫名?useUnicode=true&characterEncoding=utf8
username=XXX
password=XXX

既然使用了外部文件,那麼怎樣去讀取外部文件?

第一:創建ResourceBundle對象:

static {
        //表示加載命名爲db.properties的外部文件
		ResourceBundle resourcebundle = ResourceBundle.getBundle("db");
		driver = resourcebundle.getString("driver");
		url = resourcebundle.getString("url");
		username = resourcebundle.getString("username");
		password = resourcebundle.getString("password");
}

第二:創建類加載器,如JDBCUtils.class.getClassLoader().getResourceAsStream("db.properties");值得注意的是需要注意加載的外部文件是db.properties

static{

        try {

InputStream is =                       

JDBCUtils.class.getClassLoader().getResourceAsStream("db.properties");
			Properties prop = new Properties();
			prop.load(is);
			driver = prop.getProperty(driver);
			url = prop.getProperty(url);
			username = prop.getProperty(username);
			password = prop.getProperty(password);
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

使用連接數據庫若是我們封裝成一個工具類或是jar包,那麼以後就不需要如此的麻煩。

JDBCUtils工具包:

package utils;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import java.util.ResourceBundle;

public class JDBCUtils {
	public static String driver;
	public static String url;
	public static String username;
	public static String password;

	static {

		/*
		 * ResourceBundle resourcebundle = ResourceBundle.getBundle("db"); driver =
		 * resourcebundle.getString("driver"); url = resourcebundle.getString("url");
		 * username = resourcebundle.getString("username"); password =
		 * resourcebundle.getString("password");
		 */

		try {

			InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("db.properties");
			Properties prop = new Properties();
			prop.load(is);

			driver = prop.getProperty(driver);
			url = prop.getProperty(url);
			username = prop.getProperty(username);
			password = prop.getProperty(password);
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	public static Connection getConnection() {
		Connection conn = null;
		try {
			Class.forName(driver);
			conn = DriverManager.getConnection(url, username, password);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return conn;
	}

	public static void release(Connection conn, PreparedStatement prep, ResultSet rs) {
		if (conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}

		if (prep != null) {
			try {
				prep.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}

		if (rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}

}

這樣就能完成連接數據庫了,但是連接了數據庫,但是有一個問題,我們可以調用JDBCUtils類,但是隻有一個連接,若是有幾個同時使用這個連接,而Connection就只有一個,那麼我們可以創建一個連接池,這樣就很好的解決這個問題。

二.怎樣去創建一個連接池?

1.創建一個類去實現(implements)DataSource接口,且實現接口的衆多方法,我們重寫裏面的getConnection()方法。但在之前需要創建一個容器,private static LinkedList<Connection> pool = new LinkedList<Connection>();且寫出靜態代碼塊:

private static Connection conn = null;
可以創建多個連接,但是不能一味的多,注意考慮性能就OK
	static {
		for (int i = 0; i < 5; i++) {
			conn = JDBCUtils.getConnection();
			pool.add(conn );
		}
	}

這樣就可以去重寫getConnection()方法了,首先判斷是否還有連接,若是沒有還可以創建連接,且存在容器中,在使用連接時,可以從容器中去拿取,使用pool.remove()或是pool.removeFirst()等方法,這裏使用remove()方法,字面意思是移除,但是注意是從容器中移除,那就是從容器中拿取一個連接,在getConnection()方法中返回拿取的連接,這樣就能有多個連接可以拿取。那麼若是我們斷開一個連接之後,我們得去把它放回連接池,不然連接總有拿取完的時候,在此寫出一個方法backConnection(Connection conn),在pool.add(conn);完成放回連接。

public class MyDataSource2 implements DataSource {
	private static LinkedList<Connection> pool = new LinkedList<Connection>();
	private static Connection conn = null;
	static {
		for (int i = 0; i < 5; i++) {
			conn = JDBCUtils.getConnection();
			pool.add(conn);
		}
	}

	public Connection getConnection() throws SQLException {
		
		if (pool.isEmpty()) {
			for (int i = 0; i < 5; i++) {
			pool.add(conn);
			}
		}
		conn = pool.removeFirst();
		return conn;
	}
	public void backConnection(Connection conn) {
		pool.add(conn);
	}

在我測試之後,卻是是可以的,但是我們返回連接是看到這個backConnection有點不習慣,若是使用原生的close()多好?那把名字修改一下就OK吧,但是我們使用的不是原生的close(),若是能直接調用close()就爽了。既然我們調用的是Connection的close()方法,那麼我們就去從寫一下Connection在中的close()方法,創建一個類來實現(implements)Connection,創建容器,連接Connection,創建構造方法:

public MyConnnection(Connection conn,LinkedList<Connection> pool) {
		this.conn = conn;
		this.pool = pool;
	}

重寫close()方法:

public void close() throws SQLException {
		pool.add(conn);
	}

這樣就可以去測試了,但是去測試的時候,會發現我們在preps = conn.prepareStatement(sql);此處出現空指針異常,爲什麼呢?因爲我們改寫了Connection,所以PrepareStatement我們也得重寫:

public PreparedStatement prepareStatement(String sql) throws SQLException {
		return conn.prepareStatement(sql);
	}

既然改寫了Connection,那麼我們在連接池中也得改:

public class MyDataSource2 implements DataSource {
	private static LinkedList<Connection> pool = new LinkedList<Connection>();
	private static Connection conn = null;
	static {
		for (int i = 0; i < 5; i++) {
			conn = JDBCUtils.getConnection();
			MyConnnection myconn = new MyConnnection(conn, pool);
			pool.add(myconn);
		}
	}

	public Connection getConnection() throws SQLException {
		
		if (pool.isEmpty()) {
			for (int i = 0; i < 5; i++) {
				MyConnnection myconn = new MyConnnection(conn, pool);
				pool.add(myconn);
			}
		}
		conn = pool.removeFirst();
		return conn;
	}

和上面的MyDataSource相比,去掉backConnection()方法,且添加了我們重寫的MyConnection類,這樣就可以直接調用close()方法了。

測試jar包:junit.XX.jar和匹配jar包:hamcrest-core-XX.jar及其連接數據庫的驅動mysql-connector-XX-jar包

鏈接:https://pan.baidu.com/s/1g6Ygnu7HGPDWsfldToPRhQ 
提取碼:sp1r 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章