1.首先說明什么是JDBC
在第一眼看到這個名詞之前,我覺得有必要知道它的英文全稱是什么,Java Database Connectivity,從英文字面上理解就直譯為
可連通的Java數據庫,說白了也就是想提供一套中間環節,去連接Java代碼與數據庫,使之可以直接通過操作Java代碼就可以控制數據庫。
2.JDBC的實質
它是Java訪問數據庫的解決方案,希望能過用同樣的方式訪問不同的數據庫,以達到實現與具體數據庫無關的Java操作界面。
JDBC實質上就是就是一套標準化的接口,不同的數據庫廠商根據自己的數據庫特點去實現這套接口,實現的具體方法無需我們去關心。
JDBC中數據庫廠商實現的主要接口如下:
DriverManager :驅動管理
Connection、
DatabaseMetaData :連接接口
Statement、
PreparedStatement
CallableStatement: 語句對象接口
ResultSet、
ResultSetMetaData: 結果集接口
3.JDBC的工作原理
程序員調用的是底層數據庫廠商實現的部分,
即:1)通過Connection 接口實現第一步的連接
2)通過Statement結果傳送sql語句
3)數據庫返回結果保存到ResultSet結果集合接口中
主要流程可歸納為:
1)加載驅動,創建連接
2)創建語句對象
3)執行SQL語句
4)發回結果集
5)關閉連接
下面我以我學的oracle數據庫配合eclips為例逐步闡述一下如何實現JDBC
1)加載驅動
使用的方法為:Class.forName(“驅動”);
對于如何獲得到這個驅動,我所知道的方法是:展開JDBC的jar包,如我使用的是ojdbc6.jar,在里面找到oracle.jdbc.driver,在里面再找到OracleDriver然后鼠標右鍵點qualitycopy,粘貼到引號之中即可,如:Class.forName("oracle.jdbc.driver.OracleDriver");
2)創建連接
使用的方法為: conn=DriverManager.getConnection(“jdbc:oracle:thin:@IP地址:1521:orcl","數據庫賬號","數據庫密碼”);
如:conn=DriverManager.getConnection("jdbc:oracle:thin:@172.16.3.8:1521:orcl","jsd1601","jsd1601");
3)創建語句對象
使用的方法為:Statement stmt=conn.createStatement();
需要注意的是,使用的是第二步上面創建出來的連接去調用方法
調用executeUpdate方法將sql語句傳入其中即可執行所寫的sql語句,這里需要注意的是,executeUpdate方法能執行的sql種類為insert,update,delete
如: Statement stmt=conn.createStatement();
String sql="insert into emp_jiawenzhe(empno,ename,sal,deptno) values(1000,'賈文哲',1500,10)";
int i=stmt.executeUpdate(sql);
這里面的返回值i就是受影響的行數,我們可以根據這個受影響的行數來判斷是否操作成功
4)而對于返回的結果集主要是指進行select操作(這里暫不提)
5)最后關閉連接
如:conn.close();
列舉一整體代碼,包括注釋:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
package jdbc_day01; import java.sql.*; /** * 演示JDBC的操作步驟 * 1、加載驅動程序 * 2、創建連接 * 3、創建語句對象 * 4、發送SQL語句 * 5、如果發送的是select語句,處理結果集 * 6、關閉連接 * @author jiawenzhe * */ public class JDBCDome01 { public static void main(String[] args) throws SQLException { //需求:創建一個員工,員工號,員工名,工資,部門號 //1、 Connection conn= null ; try { Class.forName( "oracle.jdbc.driver.OracleDriver" ); System.out.println( "驅動加載成功" ); //2、 conn= DriverManager.getConnection( "jdbc:oracle:thin:@172.16.3.8:1521:orcl" , "jsd1601" , "jsd1601" ); System.out.println(conn.getClass().getName()); //3、 //Statment 語句對象。發送并執行SQL語句 /* * int excuteUpdate(String sql); * 發送insert,update,delete語句 * 返回值int表示影響數據庫表的行數 */ Statement stmt=conn.createStatement(); String sql= "insert into emp_jiawenzhe(empno,ename,sal,deptno) " + "values(1000,'王小二',1500,10)" ; int i=stmt.executeUpdate(sql); if (i> 0 ){ System.out.println( "保存成功!" ); } } catch (ClassNotFoundException e) { e.printStackTrace(); //1、記錄日志 //2、通知調用者 throw new RuntimeException( "加載驅動錯誤" ,e); } finally { //關閉連接 if (conn!= null ){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } } |
注:oracle數據庫可以使用的jar包:ojdbc14.jar/ojdbc6.jar(oracle12c用這個)
mysql數據庫可以使用的jar包:mysql-connector-java-5.0.4-bin.jar
加載驅動類:
1
|
Class.forName( "com.mysql.jdbc.Driver" ); |
1.封裝方法的引出
學了一段時間的Java給我感觸最深的就是,當前寫某一系列的代碼的時候,如果出現了代碼的復用,肯定會選擇一種方法對代碼進行一定程度的封裝,從封裝一個方法到封裝一個類,之前有提到的使用JDBC進行數據庫的操作(增,刪,改,因為查詢涉及到對結果集的操作,將單獨聲明)分為四個過程:
1)加載驅動
2)創建連接
3)創建語句對象,發送SQL
4)關閉連接
也就是說我們在進行任何對數據庫操作的時候,都要進行上述步驟,這便出現了代碼的冗余,于是便提出了封裝這些共性的步驟到一個類中,使其能成為一種工具類,為我所用
2.三個版本的封裝
1.版本1
我在學習的時候是逐步對這些類進行一個漸進性的封裝,逐步完善的,因為如果直接提出終極版的封裝,對于初學者很難接受,下面我將闡述第一種也就是最簡單的封裝方法:
你在前面會發現,無論你想如何操作數據庫,加載驅動都是必不可少的,而加載驅動里面主要就是聲明,驅動的名字,IP地址,端口號,數據庫賬戶名,密碼等等,而這些的實質就是字符串所以我將這些字符串單獨定義出來,如下面所示:
1
2
3
4
|
private static String driverclass= "oracle.jdbc.driver.OracleDriver" ; private static String url= "jdbc:oracle:thin:losthost:1521:orcl" ; private static String user= "system" ; private static String password= "123" ; |
這樣在創建連接的時候我可以直接拿到變量的名字去代替很長的字符串,而加載驅動時地方法Class.forName,我們將它聲明在靜態塊中,因為加載數據的同時,加載了驅動
如下面所示:
1
2
3
4
5
6
7
8
|
static { try { Class.forName(driverclass); } catch (ClassNotFoundException e) { e.printStackTrace(); throw new RuntimeException( "加載驅動錯誤" ,e); } } |
對于創建連接,就是調用DriverManager的getConnection方法,并將對應的用戶名,密碼放入其中,我們將這個方法直接放到我自己定義的方法中,然后直接調用我的方法便可以創建連接,需要注意的是,方法的返回值是Connection這個對象,很好理解,因為就是要拿到這個連接類型的對象,如下面所示:
1
2
3
4
5
|
public static Connection getConnection() throws SQLException{ Connection conn= DriverManager.getConnection(url,user,password); return conn; } |
然后是創建語句對象,發送SQL,當然SQL是這里面唯一特殊的地方,因為SQL要做的事千差萬別,所以這個步驟就不用封裝了。
最后是關閉連接,就是調用了close()這個方法,如下面所示
1
2
3
4
5
6
7
8
9
10
|
public static void close(Connection conn){ if (conn!= null ){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException( "關閉連接錯誤" ,e); } } } |
整體的第一版本的封裝如下面所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
package jbbc_day01; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; /** * 用來管理連接 * @author jiawenzhe * */ public class DBUtil { private static String driverclass= "oracle.jdbc.driver.OracleDriver" ; private static String url= "jdbc:oracle:thin:losthost:1521:orcl" ; private static String user= "system" ; private static String password= "123" ; //1、加載驅動 static { try { Class.forName(driverclass); } catch (ClassNotFoundException e) { e.printStackTrace(); throw new RuntimeException( "加載驅動錯誤" ,e); } } //2、創建連接 /* * 如何定義一個能夠創建連接的方法 * 返回值類型:是否有運算結果,如果有,結果的類型即為返回值類型 * 參數列表: * 方法功能中是否有不確定的數據參與運算,如果有,即為參數 */ public static Connection getConnection() throws SQLException{ Connection conn= DriverManager.getConnection(url,user,password); return conn; } //3、關閉連接 public static void close(Connection conn){ if (conn!= null ){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException( "關閉連接錯誤" ,e); } } } } |
這樣一個封裝就好了,然后在進行SQL操作的時候直接調用這個封裝類就可以了,而你只需要寫的就是創建你的語句對象,發送你的SQL語句即可
2.版本2
其實版本2與版本一很類似,就是為了去彌補版本1的一個不足之處,就是,當你更換數據庫的時候,不同數據庫的賬號密碼是不一樣的,這就要對賬號密碼和IP地址進行修改,我之前將這些以字符串的形式封裝在了工具類之中,那就意味著我們每次更換數據庫必須對工具類進行修改,這樣是很不妥當的,于是提出了一種改進辦法就是將這些連接數據放到一個配置文件之中,工具類去讀取這個配置文件,我們在修改的時候直接去修改這個配置文件就可以了
在介紹這個版本之前,我前引出一個新類就是Properties,他就是一個能讀取文件,并以流的形式去讀取配置文件內容然后返回給工具類的
首先我先把配置文件示例出來,其實不用解釋,一目了然,如下所示:
1
2
3
4
|
jdbc.driverclass=oracle.jdbc.driver.OracleDriver jdbc.url=jdbc:oracle:thin:localhost:orcl jdbc.user=system jdbc.password= 123 |
前面是鍵,后面是值,前面的鍵值是我們自己定義的,就像定義變量名字一樣,后面的值就是我們數據庫的實際情況,這里我們需要特別注意的是,這個配置文件的后綴名一定要以.properties結尾,因為這樣Properties這個類才能讀取的到。
這部分的示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
static { try { //加載屬性文件數據 Properties pop= new Properties(); pop.load(DBUtil2. class .getClassLoader().getResourceAsStream( "db.properties" )); url=pop.getProperty( "jdbc.url" ); driverclass=pop.getProperty( "jdbc.driverclass" ); user=pop.getProperty( "jdbc.user" ); password=pop.getProperty( "jdbc.password" ); Class.forName(driverclass); } catch (ClassNotFoundException e) { e.printStackTrace(); throw new RuntimeException( "加載驅動錯誤" ,e); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } |
load()這個方法就是去讀取也可以認為是加載配置文件的,這個整整一句話記住就行,不用去深究其意義,而getProperty()就是通過鍵獲得到了對應的值,很像鍵值對集合獲取值得形式
整體代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
package jbbc_day01; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties; /** * 用來管理連接 * 數據庫連接信息,保存在屬性文件中 * @author jiawenzhe * */ public class DBUtil2 { private static String driverclass; private static String url; private static String user; private static String password; //1、加載驅動 static { try { //加載屬性文件數據 Properties pop= new Properties(); pop.load(DBUtil2. class .getClassLoader().getResourceAsStream( "db.properties" )); url=pop.getProperty( "jdbc.url" ); driverclass=pop.getProperty( "jdbc.driverclass" ); user=pop.getProperty( "jdbc.user" ); password=pop.getProperty( "jdbc.password" ); Class.forName(driverclass); } catch (ClassNotFoundException e) { e.printStackTrace(); throw new RuntimeException( "加載驅動錯誤" ,e); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //2、創建連接 /* * 如何定義一個能夠創建連接的方法 * 返回值類型:是否有運算結果,如果有,結果的類型即為返回值類型 * 參數列表: * 方法功能中是否有不確定的數據參與運算,如果有,即為參數 */ public static Connection getConnection() throws SQLException{ Connection conn= DriverManager.getConnection(url,user,password); return conn; } //3、關閉連接 public static void close(Connection conn){ if (conn!= null ){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException( "關閉連接錯誤" ,e); } } } } |