數據庫連接JDBC
在Java中,數據庫存取技術可分爲如下幾類:
- JDBC直接訪問數據庫
- JDO技術
- 第三方O/R工具,如Hibernate, ibatis 等
JDBC(Java Database Connectivity)是一個獨立於特定數據庫管理系統、通用的SQL數據庫存取和操作的公共接口(一組API),定義了用來訪問數據庫的標準Java類庫,(java.sql,javax.sql)使用這個類庫可以以一種標準的方法、方便地訪問數據庫資源。JDBC爲訪問不同的數據庫提供了一種統一的途徑,爲開發者屏蔽了一些細節問題。JDBC的目標是使Java程序員使用JDBC可以連接任何提供了JDBC驅動程序的數據庫系統,這樣就使得程序員無需對特定的數據庫系統的特點有過多的瞭解,從而大大簡化和加快了開發過程。
當然也可以不使用統一的JDBC接口分別使用不同的數據庫廠商各自的驅動,但這樣就不能體現Java的可移植性了。
JDBC是sun公司提供一套用於數據庫操作的接口,java程序員只需要面向這套接口編程即可。不同的數據庫廠商,需要針對這套接口,提供不同實現。不同的實現的集合,即爲不同數據庫的驅動。-----面向接口編程
即
JDBC:一套用於數據庫操作的接口
JDBC驅動:需要針對這套接口,提供不同實現。不同的實現的集合,即爲不同數據庫的驅動
JDBC接口(API)包括兩個層次:
面向應用的API:Java API,抽象接口,供應用程序開發人員使用(連接數據庫,執行SQL語句,獲得結果)。
面向數據庫的API:Java Driver API,供開發商開發數據庫驅動程序用。
這是通過JDBC連接數據庫的幾種方式,也是從繁到簡的一個過程:
JDBCTest.java
public class JDBCTest {
//版本4.0 最終版
@Test
public void test4() throws Exception{
Properties pros = new Properties();
pros.load(this.getClass().getClassLoader().getResourceAsStream("com/atguigu/jdbc/jdbc.properties"));
String driverClassName = pros.getProperty("driverClassName");
String url = pros.getProperty("url");
String user = pros.getProperty("user");
String password = pros.getProperty("password");
//1. 加載驅動
Class.forName(driverClassName);
//2. 獲取連接
Connection conn = DriverManager.getConnection(url, user, password);
System.out.println(conn);
}
//版本3.0
@Test
public void test3() throws Exception{
String driverClassName = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://127.0.0.1:3306/test";
String user = "root";
String password = "123456";
/*
* 通常不用顯式調用 DriverManager 類的 registerDriver()
* 方法來註冊驅動程序類的實例,因爲 Driver 接口的驅動程序類都包含了靜態代碼塊,
* 在這個靜態代碼塊中,隨類加載而加載,即Class類加載時就加載了驅動,所以它會
* 會調用 DriverManager.registerDriver() 方法來註冊自身的一個實例
*/
//1. 加載驅動
Class.forName(driverClassName);
//2. 獲取連接
Connection conn = DriverManager.getConnection(url, user, password);
System.out.println(conn);
}
//版本2.0 利用 DriverManager(驅動管理類),獲取數據庫連接
@Test
public void test2() throws Exception{
String driverClassName = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://127.0.0.1:3306/test";
String user = "root";
String password = "123456";
//1. 註冊驅動
Driver driver = null;
Class clazz = Class.forName(driverClassName);
driver = (Driver) clazz.newInstance();
DriverManager.registerDriver(driver);
//2. 獲取連接
Connection conn = DriverManager.getConnection(url, user, password);
System.out.println(conn);
}
//版本1.0 利用反射,根據 MySQL 廠商提供的驅動,獲取 MySQL 數據庫的連接
@Test
public void test1() throws Exception{
String driverClassName = "com.mysql.jdbc.Driver";
//1. 獲取驅動
Driver driver = null;
Class clazz = Class.forName(driverClassName);
driver = (Driver) clazz.newInstance();
//2. 獲取連接
String url = "jdbc:mysql://127.0.0.1:3306/test";
Properties info = new Properties();
info.setProperty("user", "root");
info.setProperty("password", "123456");
Connection conn = driver.connect(url, info);
System.out.println(conn);
}
}
數據庫連接池c3p0、dhcp
在使用開發基於數據庫的web程序時,傳統的模式(JDBC)基本是按以下步驟:
- 在主程序(如servlet、beans)中建立數據庫連接
- 進行sql操作
- 斷開數據庫連接
普通的JDBC數據庫連接使用 DriverManager 來獲取,每次向數據庫建立連接的時候都要將 Connection 加載到內存中,再驗證用戶名和密碼(得花費0.05s~1s的時間)。需要數據庫連接的時候,就向數據庫要求一個,執行完成後再斷開連接。這樣的方式將會消耗大量的資源和時間。數據庫的連接資源並沒有得到很好的重複利用.若同時有幾百人甚至幾千人在線,頻繁的進行數據庫連接操作將佔用很多的系統資源,嚴重的甚至會造成服務器的崩潰。
對於每一次數據庫連接,使用完後都得斷開。否則,如果程序出現異常而未能關閉,將會導致數據庫系統中的內存泄漏,最終將導致重啓數據庫。
這種開發不能控制被創建的連接對象數,系統資源會被毫無顧及的分配出去,如連接過多,也可能導致內存泄漏,服務器崩潰。
爲解決傳統開發中的數據庫連接問題,可以採用數據庫連接池技術。
數據庫連接池的基本思想就是爲數據庫連接建立一個“緩衝池”。預先在緩衝池中放入一定數量的連接,當需要建立數據庫連接時,只需從“緩衝池”中取出一個,使用完畢之後再放回去。
數據庫連接池負責分配、管理和釋放數據庫連接,它允許應用程序重複使用一個現有的數據庫連接,而不是重新建立一個。
數據庫連接池在初始化時將創建一定數量的數據庫連接放到連接池中,這些數據庫連接的數量是由最小數據庫連接數來設定的。無論這些數據庫連接是否被使用,連接池都將一直保證至少擁有這麼多的連接數量。連接池的最大數據庫連接數量限定了這個連接池能佔有的最大連接數,當應用程序向連接池請求的連接數超過最大連接數量時,這些請求將被加入到等待隊列中。
JDBC 的數據庫連接池使用 javax.sql.DataSource 來表示,DataSource 只是一個接口,該接口通常由服務器(Weblogic, WebSphere, Tomcat)提供實現,也有一些開源組織提供實現:
- DBCP 數據庫連接池
- C3P0 數據庫連接池
DataSource用來取代DriverManager來獲取Connection,獲取速度快,同時可以大幅度提高數據庫訪問速度。
DHCP數據源
DBCP 是 Apache 軟件基金組織下的開源連接池實現,該連接池依賴該組織下的另一個開源系統:Common-pool. 如需使用該連接池實現,應在系統中增加如下兩個 jar 文件:
Commons-dbcp.jar:連接池的實現
Commons-pool.jar:連接池實現的依賴庫
Tomcat 的連接池正是採用該連接池來實現的。該數據庫連接池既可以與應用服務器整合使用,也可由應用程序獨立使用。
數據源和數據庫連接不同,數據源無需創建多個,它是產生數據庫連接的工廠,因此整個應用只需要一個數據源即可。
當數據庫訪問結束後,程序還是像以前一樣關閉數據庫連接:conn.close(); 但上面的代碼並沒有關閉數據庫的物理連接,它僅僅把數據庫連接釋放,歸還給了數據庫連接池。
兩種連接池分別有兩種方式創建數據庫的連接
DataSourceTest.java
public class DataSourceTest {
//使用 C3P0 方式二:
@Test
public void test4() throws SQLException{
DataSource ds = new ComboPooledDataSource("helloc3p0");
Connection conn = ds.getConnection();
System.out.println(conn);
}
//使用 C3P0 方式一:
@Test
public void test3() throws Exception{
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass("com.mysql.jdbc.Driver");
cpds.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/test");
cpds.setUser("root");
cpds.setPassword("123456");
Connection conn = cpds.getConnection();
System.out.println(conn);
}
//使用 DBCP 方式二:
@Test
public void test2() throws Exception{
Properties pros = new Properties();
pros.load(DataSourceTest.class.getClassLoader().getResourceAsStream("dbcp.properties"));
DataSource ds = BasicDataSourceFactory.createDataSource(pros);
Connection conn = ds.getConnection();
System.out.println(conn);
}
//使用 DBCP 方式一:
@Test
public void test1() throws SQLException{
BasicDataSource bds = new BasicDataSource();
bds.setDriverClassName("com.mysql.jdbc.Driver");
bds.setUrl("jdbc:mysql://127.0.0.1:3306/test");
bds.setUsername("root");
bds.setPassword("123456");
bds.setInitialSize(10);
bds.setMaxActive(10);
Connection conn = bds.getConnection();
System.out.println(conn);
//將連接放回到連接池中
conn.close();
}
}
使用方式二的c3p0需要一個配置文件(當然也可以用屬性文件),且配置文件的名字必須是c3p0-config.xml,因爲數據庫廠商底層是根據key-value來封裝數據的,所以會根據這個key來進行匹配讀取,而且必須放在src的路徑下,因爲讀取是通過類加載器的方式進行讀取的。使用方式二的dhcp需要一個屬性文件和jdbc的屬性文件大致一樣,就不多贅述了
c3p0-config.xml
<c3p0-config>
<named-config name="helloc3p0">
<!-- 連接數據庫的四個字符串 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/test</property>
<property name="user">root</property>
<property name="password">123456</property>
<!-- 若連接池滿了一次增長几個 -->
<property name="acquireIncrement">5</property>
<!-- 連接池初始大小 -->
<property name="initialPoolSize">10</property>
<!-- 連接池中最小連接數 -->
<property name="minPoolSize">5</property>
<!-- 連接池中最大連接數 -->
<property name="maxPoolSize">10</property>
<!-- 整個連接池中最多管理的 Statement 的個數 -->
<property name="maxStatements">10</property>
<!-- 連接池中每個連接最多管理的 Statement 的個數 -->
<property name="maxStatementsPerConnection">2</property>
</named-config>
</c3p0-config>
注意:配置文件的 <named-config name="helloc3p0"> 的名字要和DataSource ds = new ComboPooledDataSource("helloc3p0");要傳入的參數一致。