JDBC是一種用于執(zhí)行SQL語句的Java API,可以為多種關(guān)系數(shù)據(jù)庫提供統(tǒng)一訪問,它由一組用Java語言編寫的類和接口組成。JDBC提供了一種基準(zhǔn),據(jù)此可以構(gòu)建更高級的工具和接口,使數(shù)據(jù)庫開發(fā)人員能夠編寫數(shù)據(jù)庫應(yīng)用程序,同時,JDBC也是個商標(biāo)名。
有了JDBC,向各種關(guān)系數(shù)據(jù)發(fā)送SQL語句就是一件很容易的事。換言之,有了JDBC API,就不必為訪問Sybase數(shù)據(jù)庫專門寫一個程序,為訪問Oracle數(shù)據(jù)庫又專門寫一個程序,或為訪問Informix數(shù)據(jù)庫又編寫另一個程序等等,程序員只需用JDBC API寫一個程序就夠了,它可向相應(yīng)數(shù)據(jù)庫發(fā)送SQL調(diào)用。同時,將Java語言和JDBC結(jié)合起來使程序員不必為不同的平臺編寫不同的應(yīng)用程序,只須寫一遍程序就可以讓它在任何平臺上運行,這也是Java語言“編寫一次,處處運行”的優(yōu)勢。
Java數(shù)據(jù)庫連接體系結(jié)構(gòu)是用于Java應(yīng)用程序連接數(shù)據(jù)庫的標(biāo)準(zhǔn)方法。JDBC對Java程序員而言是API,對實現(xiàn)與數(shù)據(jù)庫連接的服務(wù)提供商而言是接口模型。作為API,JDBC為程序開發(fā)提供標(biāo)準(zhǔn)的接口,并為數(shù)據(jù)庫廠商及第三方中間件廠商實現(xiàn)與數(shù)據(jù)庫的連接提供了標(biāo)準(zhǔn)方法。JDBC使用已有的SQL標(biāo)準(zhǔn)并支持與其它數(shù)據(jù)庫連接標(biāo)準(zhǔn),如ODBC之間的橋接。JDBC實現(xiàn)了所有這些面向標(biāo)準(zhǔn)的目標(biāo)并且具有簡單、嚴(yán)格類型定義且高性能實現(xiàn)的接口。
Java 具有堅固、安全、易于使用、易于理解和可從網(wǎng)絡(luò)上自動下載等特性,是編寫數(shù)據(jù)庫應(yīng)用程序的杰出語言。所需要的只是 Java應(yīng)用程序與各種不同數(shù)據(jù)庫之間進(jìn)行對話的方法。而 JDBC 正是作為此種用途的機(jī)制。
JDBC 擴(kuò)展了 Java 的功能。例如,用 Java 和 JDBC API 可以發(fā)布含有 applet 的網(wǎng)頁,而該 applet 使用的信息可能來自遠(yuǎn)程數(shù)據(jù)庫。企業(yè)也可以用 JDBC 通過 Intranet 將所有職員連到一個或多個內(nèi)部數(shù)據(jù)庫中(即使這些職員所用的計算機(jī)有 Windows、 Macintosh 和UNIX 等各種不同的操作系統(tǒng))。隨著越來越多的程序員開始使用Java 編程語言,對從 Java 中便捷地訪問數(shù)據(jù)庫的要求也在日益增加。
MIS管理員們都喜歡 Java 和 JDBC 的結(jié)合,因為它使信息傳播變得容易和經(jīng)濟(jì)。企業(yè)可繼續(xù)使用它們安裝好的數(shù)據(jù)庫,并能便捷地存取信息,即使這些信息是儲存在不同數(shù)據(jù)庫管理系統(tǒng)上。新程序的開發(fā)期很短。安裝和版本控制將大為簡化。程序員可只編寫一遍應(yīng)用程序或只更新一次,然后將它放到服務(wù)器上,隨后任何人就都可得到最新版本的應(yīng)用程序。對于商務(wù)上的銷售信息服務(wù), Java 和JDBC 可為外部客戶提供獲取信息更新的更好方法。
一、數(shù)據(jù)庫連接池:
在一般用JDBC 進(jìn)行連接數(shù)據(jù)庫進(jìn)行CRUD操作時,每一次都會:
通過:java.sql.Connection conn = DriverManager.getConnection(url,user,password); 重新獲取一個數(shù)據(jù)庫的鏈接再進(jìn)行操作,這樣用戶每次請求都需要向數(shù)據(jù)庫獲得鏈接,而數(shù)據(jù)庫創(chuàng)建連接通常需要消耗相對較大的資源,創(chuàng)建時間也較長。
所以為了減少服務(wù)器的壓力,便可用連接池的方法:在啟動Web應(yīng)用時,數(shù)據(jù)就創(chuàng)建好一定數(shù)量的Connection鏈接
存放到一個容器中,然后當(dāng)用戶請求時,服務(wù)器則向容器中獲取Connection鏈接來處理用戶的請求,當(dāng)用戶的請求完成后,
又將該Connection 鏈接放回到該容器中。這樣的一個容器稱為連接池。
編寫一個基本的連接池實現(xiàn)連接復(fù)用
步驟:
1、建立一個數(shù)據(jù)庫連接池容器。(因為方便存取,則使用LinkedList集合)
2、初始化一定數(shù)量的連接,放入到容器中。
3、等待用戶獲取連接對象。(該部分要加鎖)
|---記得刪除容器中對應(yīng)的對象,放置別人同時獲取到同一個對象。
4、提供一個方法,回收用戶用完的連接對象。
5、要遵循先入先出的原則。
1 import java.io.InputStream;
2 import java.sql.Connection;
3 import java.sql.DriverManager;
4 import java.sql.SQLException;
5 import java.util.LinkedList;
6 import java.util.Properties;
7
8
9 /**
10 * 一個基本的數(shù)據(jù)連接池:
11 * 1、初始化時就建立一個容器,來存儲一定數(shù)量的Connection 對象
12 * 2、用戶通過調(diào)用MyDataSource 的getConnection 來獲取Connection 對象。
13 * 3、再通過release 方法來回收Connection 對象,而不是直接關(guān)閉連接。
14 * 4、遵守先進(jìn)先出的原則。
15 *
16 *
17 * @author 賀佐安
18 *
19 */
20 public class MyDataSource {
21 private static String url = null;
22 private static String password = null;
23 private static String user = null ;
24 private static String DriverClass = null;
25 private static LinkedList《Connection》 pool = new LinkedList《Connection》() ;
26 // 注冊數(shù)據(jù)庫驅(qū)動
27 static {
28 try {
29 InputStream in = MyDataSource.class.getClassLoader()
30 .getResourceAsStream(“db.properties”);
31 Properties prop = new Properties();
32 prop.load(in);
33 user = prop.getProperty(“user”);
34 url = prop.getProperty(“url”) ;
35 password = prop.getProperty(“password”) ;
36 DriverClass = prop.getProperty(“DriverClass”) ;
37 Class.forName(DriverClass) ;
38
39 } catch (Exception e) {
40 throw new RuntimeException(e) ;
41 }
42 }
43 //初始化建立數(shù)據(jù)連接池
44 public MyDataSource () {
45 for(int i = 0 ; i 《 10 ; i ++) {
46 try {
47 Connection conn = DriverManager.getConnection(url, user, password) ;
48 pool.add(conn) ;
49 } catch (SQLException e) {
50 e.printStackTrace();
51 }
52 }
53 }
54 //、從連接池獲取連接
55 public Connection getConnection() throws SQLException {
56 return pool.remove() ;
57 }
58 // 回收連接對象。
59 public void release(Connection conn) {
60 System.out.println(conn+“被回收”);
61 pool.addLast(conn) ;
62 }
63 public int getLength() {
64 return pool.size() ;
65 }
66 }
這樣當(dāng)我們要使用Connection 連接數(shù)據(jù)庫時,則可以直接使用連接池中Connection 的對象。測試如下:
1 import java.sql.Connection;
2 import java.sql.SQLException;
3
4 import org.junit.Test;
5
6
7 public class MyDataSourceTest {
8
9
10 /**
11 * 獲取數(shù)據(jù)庫連接池中的所有連接。
12 */
13 @Test
14 public void Test() {
15 MyDataSource mds = new MyDataSource() ;
16 Connection conn = null ;
17 try {
18
19 for (int i = 0 ; i 《 20 ; i ++) {
20 conn = mds.getConnection() ;
21 System.out.println(conn+“被獲?。贿B接池還有:”+mds.getLength());
22 mds.release(conn) ;
23 }
24 } catch (SQLException e) {
25 e.printStackTrace();
26 }
27 }
28 }
再運行的時候,可以發(fā)現(xiàn),循環(huán)10次后,又再一次獲取到了第一次循環(huán)的得到的Connection對象。所以,這樣可以大大的減輕數(shù)據(jù)庫的壓力。上面只是一個簡單的數(shù)據(jù)庫連接池,不完美的便是,回收需要調(diào)用數(shù)據(jù)池的release() 方法來進(jìn)行回收,那么可以不可以直接調(diào)用Connection 實例的close 便完成Connection 對象的回收呢?
二、數(shù)據(jù)源:
》 編寫連接池需實現(xiàn)javax.sql.DataSource接口。
》 實現(xiàn)DataSource接口,并實現(xiàn)連接池功能的步驟:
1、在DataSource構(gòu)造函數(shù)中批量創(chuàng)建與數(shù)據(jù)庫的連接,并把創(chuàng)建的連接加入LinkedList對象中。
2、實現(xiàn)getConnection方法,讓getConnection方法每次調(diào)用時,從LinkedList中取一個Connection返回給用戶。當(dāng)用戶使用完Connection,調(diào)用Connection.close()方法時,Collection對象應(yīng)保證將自己返回到LinkedList中,而不要把conn還給數(shù)據(jù)庫。
利用動態(tài)代理和包裝設(shè)計模式來標(biāo)準(zhǔn)的數(shù)據(jù)源。
1、包裝設(shè)計模式實現(xiàn)標(biāo)準(zhǔn)數(shù)據(jù)源:
這里的用包裝設(shè)計模式,便是將Connection 接口進(jìn)行包裝。簡單總結(jié)一下包裝設(shè)計模式的步驟:
a)定義一個類,實現(xiàn)與被包裝類()相同的接口。
|----可以先自己寫一個適配器,然后后面繼承這個適配器,改寫需要改寫的方法,提高編程效率。
b)定義一個實例變量,記住被包裝類的對象的引用。
c)定義構(gòu)造方法,轉(zhuǎn)入被包裝類的對象。
e)對需要改寫的方法,改寫。
f)對不需要改寫的方法,調(diào)用原來被包裝類的對應(yīng)方法。
所以先編寫一個類似適配器的類,將Connection 接口的方法都進(jìn)行實現(xiàn):
View Code
然后再對Connection 接口進(jìn)行包裝,將close 方法修改掉:
1 import java.sql.Connection;
2 import java.sql.SQLException;
3 import java.util.LinkedList;
4 /**
5 * 對MyConnectionAdapter 進(jìn)行包裝處理
6 * @author 賀佐安
7 *
8 */
9 public class MyConnectionWrap extends MyConnectionAdapter {
10
11 private LinkedList《Connection》 pool = new LinkedList《Connection》() ;
12 public MyConnectionWrap(Connection conn ,LinkedList《Connection》 pool ) {
13 super(conn);
14 this.pool = pool ;
15 }
16
17 //改寫要實現(xiàn)的方法
18 public void close() throws SQLException {
19 pool.addLast(conn) ;
20 }
21 }
編寫標(biāo)準(zhǔn)數(shù)據(jù)源:
1 import java.io.PrintWriter;
2 import java.sql.Connection;
3 import java.sql.DriverManager;
4 import java.sql.SQLException;
5 import java.util.LinkedList;
6 import java.util.ResourceBundle;
7
8 import javax.sql.DataSource;
9
10
11 /**
12 * 編寫標(biāo)準(zhǔn)的數(shù)據(jù)源:
13 * 1、實現(xiàn)DataSource 接口
14 * 2、獲取在實現(xiàn)類的構(gòu)造方法中批量獲取Connection 對象,并將這些Connection 存儲
15 * 在LinkedList 容器中。
16 * 3、實現(xiàn)getConnection() 方法,調(diào)用時返回LinkedList容器的Connection對象給用戶。
17 * @author 賀佐安
18 *
19 */
20 public class MyDataSource implements DataSource{
21 private static String url = null;
22 private static String password = null;
23 private static String user = null ;
24 private static String DriverClass = null;
25 private static LinkedList《Connection》 pool = new LinkedList《Connection》() ;
26
27 // 注冊數(shù)據(jù)庫驅(qū)動
28 static {
29 try {
30 ResourceBundle rb = ResourceBundle.getBundle(“db”) ;
31 url = rb.getString(“url”) ;
32 password = rb.getString(“password”) ;
33 user = rb.getString(“user”) ;
34 DriverClass = rb.getString(“DriverClass”) ;
35 Class.forName(DriverClass) ;
36
37 //初始化建立數(shù)據(jù)連接池
38 for(int i = 0 ; i 《 10 ; i ++) {
39 Connection conn = DriverManager.getConnection(url, user, password) ;
40 pool.add(conn) ;
41 }
42 } catch (Exception e) {
43 throw new RuntimeException(e) ;
44 }
45
46 }
47 public MyDataSource () {
48 }
49
50 //、從連接池獲取連接:通過包裝模式
51 public synchronized Connection getConnection() throws SQLException {
52 if (pool.size() 》 0) {
53 MyConnectionWrap mcw = new MyConnectionWrap(pool.remove(), pool) ;
54 return mcw ;
55 }else {
56 throw new RuntimeException(“服務(wù)器繁忙!”);
57 }
58 }
59
60 // 回收連接對象。
61 public void release(Connection conn) {
62 System.out.println(conn+“被回收”);
63 pool.addLast(conn) ;
64 }
65
66 public int getLength() {
67 return pool.size() ;
68 }
69
70
71 @Override
72 public PrintWriter getLogWriter() throws SQLException {
73 return null;
74 }
75 @Override
76 public void setLogWriter(PrintWriter out) throws SQLException {
77
78 }
79 @Override
80 public void setLoginTimeout(int seconds) throws SQLException {
81
82 }
83 @Override
84 public int getLoginTimeout() throws SQLException {
85 return 0;
86 }
87 @Override
88 public 《T》 T unwrap(Class《T》 iface) throws SQLException {
89 return null;
90 }
91 @Override
92 public boolean isWrapperFor(Class《?》 iface) throws SQLException {
93 return false;
94 }
95 @Override
96 public Connection getConnection(String username, String password)
97 throws SQLException {
98 return null;
99 }
100
101 }
2、動態(tài)代理實現(xiàn)標(biāo)準(zhǔn)數(shù)據(jù)源:
相對于用包裝設(shè)計來完成標(biāo)準(zhǔn)數(shù)據(jù)源,用動態(tài)代理則方便許多:
1 import java.io.PrintWriter;
2 import java.lang.reflect.InvocationHandler;
3 import java.lang.reflect.Method;
4 import java.lang.reflect.Proxy;
5 import java.sql.Connection;
6 import java.sql.DriverManager;
7 import java.sql.SQLException;
8 import java.util.LinkedList;
9 import java.util.ResourceBundle;
10
11 import javax.sql.DataSource;
12
13
14 /**
15 * 編寫標(biāo)準(zhǔn)的數(shù)據(jù)源:
16 * 1、實現(xiàn)DataSource 接口
17 * 2、獲取在實現(xiàn)類的構(gòu)造方法中批量獲取Connection 對象,并將這些Connection 存儲
18 * 在LinkedList 容器中。
19 * 3、實現(xiàn)getConnection() 方法,調(diào)用時返回LinkedList容器的Connection對象給用戶。
20 * @author 賀佐安
21 *
22 */
23 public class MyDataSource implements DataSource{
24 private static String url = null;
25 private static String password = null;
26 private static String user = null ;
27 private static String DriverClass = null;
28 private static LinkedList《Connection》 pool = new LinkedList《Connection》() ;
29
30 // 注冊數(shù)據(jù)庫驅(qū)動
31 static {
32 try {
33 ResourceBundle rb = ResourceBundle.getBundle(“db”) ;
34 url = rb.getString(“url”) ;
35 password = rb.getString(“password”) ;
36 user = rb.getString(“user”) ;
37 DriverClass = rb.getString(“DriverClass”) ;
38 Class.forName(DriverClass) ;
39
40 //初始化建立數(shù)據(jù)連接池
41 for(int i = 0 ; i 《 10 ; i ++) {
42 Connection conn = DriverManager.getConnection(url, user, password) ;
43 pool.add(conn) ;
44 }
45 } catch (Exception e) {
46 throw new RuntimeException(e) ;
47 }
48 }
49 public MyDataSource () {
50
51 }
52
53 //、從連接池獲取連接:通過動態(tài)代理
54 public Connection getConnection() throws SQLException {
55 if (pool.size() 》 0) {
56 final Connection conn = pool.remove() ;
57 Connection proxyCon = (Connection) Proxy.newProxyInstance(conn.getClass().getClassLoader(), conn.getClass().getInterfaces(),
58 new InvocationHandler() {
59 //策略設(shè)計模式:
60 @Override
61 public Object invoke(Object proxy, Method method, Object[] args)
62 throws Throwable {
63 if(“close”.equals(method.getName())){
64 //誰調(diào)用,
65 return pool.add(conn);//當(dāng)調(diào)用close方法時,攔截了,把鏈接放回池中了
66 }else{
67 return method.invoke(conn, args);
68 }
69 }
70 });
71 return proxyCon ;
72 }else {
73 throw new RuntimeException(“服務(wù)器繁忙!”);
74 }
75 }
76
77 public int getLength() {
78 return pool.size() ;
79 }
80
81
82 @Override
83 public PrintWriter getLogWriter() throws SQLException {
84 return null;
85 }
86 @Override
87 public void setLogWriter(PrintWriter out) throws SQLException {
88
89 }
90 @Override
91 public void setLoginTimeout(int seconds) throws SQLException {
92
93 }
94 @Override
95 public int getLoginTimeout() throws SQLException {
96 return 0;
97 }
98 @Override
99 public 《T》 T unwrap(Class《T》 iface) throws SQLException {
100 return null;
101 }
102 @Override
103 public boolean isWrapperFor(Class《?》 iface) throws SQLException {
104 return false;
105 }
106 @Override
107 public Connection getConnection(String username, String password)
108 throws SQLException {
109 return null;
110 }
111 }
當(dāng)然覺得麻煩的則可以直接使用一些開源的數(shù)據(jù)源如:DBCP、C3P0等。DBCP的原理是用包裝設(shè)計模式開發(fā)的數(shù)據(jù)源,而C3P0則是動態(tài)代理的。
1、DBCP的使用:
1 import java.io.InputStream;
2 import java.sql.Connection;
3 import java.sql.SQLException;
4 import java.util.Properties;
5
6 import javax.sql.DataSource;
7
8 import org.apache.commons.dbcp.BasicDataSourceFactory;
9
10 /**
11 * 創(chuàng)建DBCP 工具類
12 * @author 賀佐安
13 *
14 */
15 public class DbcpUtil {
16 private static DataSource ds = null ;
17 static {
18 try {
19 //讀取配置文件
20 InputStream in = DbcpUtil.class.getClassLoader().getResourceAsStream(“dbcpconfig.properties”) ;
21 Properties prop = new Properties() ;
22 prop.load(in) ;
23
24 //通過BasicDataSourceFactory 的creatDataSurce 方法創(chuàng)建 BasicDataSource 對象。
25 ds = BasicDataSourceFactory.createDataSource(prop) ;
26
27 } catch (Exception e) {
28 e.printStackTrace();
29 }
30 }
31 public static DataSource getDs() {
32 return ds ;
33 }
34 public static Connection getConnection () {
35 try {
36 return ds.getConnection() ;
37 } catch (SQLException e) {
38 throw new RuntimeException() ;
39 }
40 }
41 }
2、C3P0 的使用:
1 import java.sql.Connection;
2 import java.sql.SQLException;
3
4 import com.mchange.v2.c3p0.ComboPooledDataSource;
5 /**
6 * C3P0 開源數(shù)據(jù)源的使用
7 * @author 賀佐安
8 *
9 */
10 public class C3p0Util {
11 private static ComboPooledDataSource cpds = null ;
12 static {
13
14 cpds = new ComboPooledDataSource() ;
15 }
16 public static Connection getConnection() {
17 try {
18 return cpds.getConnection() ;
19 } catch (SQLException e) {
20 throw new RuntimeException() ;
21 }
22 }
23 }
使用這兩個數(shù)據(jù)源時,直接調(diào)用獲取到的Connection 連接的close 方法,也是將連接放到pool中去。
三、元數(shù)據(jù)(DatabaseMetaData)信息的獲取
》 元數(shù)據(jù):數(shù)據(jù)庫、表、列的定義信息。
》 元數(shù)據(jù)信息的獲?。簽榱司帉慗DBC框架使用。
1、數(shù)據(jù)庫本身信息的獲?。簀ava.sql.DataBaseMateData java.sql.Connection.getMetaData() ;
DataBaseMateData 實現(xiàn)類的常用方法:
getURL():返回一個String類對象,代表數(shù)據(jù)庫的URL。
getUserName():返回連接當(dāng)前數(shù)據(jù)庫管理系統(tǒng)的用戶名。
getDatabaseProductName():返回數(shù)據(jù)庫的產(chǎn)品名稱。
getDatabaseProductVersion():返回數(shù)據(jù)庫的版本號。
getDriverName():返回驅(qū)動驅(qū)動程序的名稱。
getDriverVersion():返回驅(qū)動程序的版本號。
isReadOnly():返回一個boolean值,指示數(shù)據(jù)庫是否只允許讀操作。
2、ParameterMetaData: 代表PerparedStatment 中的SQL 參數(shù)元數(shù)據(jù)信息: java.sql.ParameterMetaData java.sql.PerparedStatement.getParameterMetaData() ;
ParameterMetaData 實現(xiàn)類常用方法:
getParameterCount() :獲得指定參數(shù)的個數(shù)
getParameterType(int param) :獲得指定參數(shù)的sql類型(驅(qū)動可能不支持)
3、ResultSetMetaData : 代表結(jié)果集的源數(shù)據(jù)信息:相當(dāng)于SQL 中的 :DESC java.sql.ResultSetMetaData java.sql.ResultSet.getMetaData() ;
java.sql.ResultSetMetaData 接口中常用的方法:
a) getColumnCount() : 獲取查詢方法有幾列。
b) getColumnName(int index) : 獲取列名:index從1開始。
c) getColumnType(int index) : 獲取列的數(shù)據(jù)類型。返回的是TYPES 中的常量值。
四、編寫自己的JDBC框架:
JDBC框架的基本組成:
1、核心類:
a、定義一個指定javax.sql.DataSource 實例的引用變量,通過構(gòu)造函數(shù)獲取指定的實例并給定義的變量。
b、編寫SQL運行框架。
DML 語句的編寫:
1、通過獲取的javax.sql.DataSource 實例,獲取Connection 對象。
2、通過ParamenterMeteData 獲取數(shù)據(jù)庫元數(shù)據(jù)。
DQL 語句的編寫:
1、通過獲取的DataSource 實例,獲取Connection 對象。
2、通過ParamenterMeteData、ResultSetMetaData 等獲取數(shù)據(jù)庫元數(shù)據(jù)。
3、用抽象策略設(shè)計模式:設(shè)計一個ResultSetHandler 接口,作用:將查找出的數(shù)據(jù)封裝到指定的JavaBean中。
|————這里的JavaBean,由用戶來指定。
抽象策略模式,用戶可以更具具體的功能來擴(kuò)展成具體策略設(shè)計模式。如:查找的一條信息、查找的所有信息。
1 import java.sql.Connection;
2 import java.sql.ParameterMetaData;
3 import java.sql.PreparedStatement;
4 import java.sql.ResultSet;
5 import java.sql.SQLException;
6 import java.sql.Statement;
7
8 import javax.sql.DataSource;
9
10 /**
11 * 實現(xiàn)JDBC 框架的核心類。
12 * 在該類中定義了SQL語句完成的方法;
13 * @author 賀佐安
14 *
15 */
16 public class MyJdbcFrame {
17 /**
18 * javax.sql.DataSource 實例的引用變量
19 */
20 private DataSource ds = null ;
21 /**
22 * 將用戶指定的DataSource 指定給系統(tǒng)定義的DataSource 實例的引用變量
23 * @param ds
24 */
25 public MyJdbcFrame(DataSource ds ) {
26 this.ds = ds ;
27 }
28 /**
29 * 執(zhí)行UPDATE、DELETE、INSERT 語句。
30 * @param sql
31 * @param obj
32 */
33 public void update(String sql , Object[] obj) {
34 Connection conn = null ;
35 PreparedStatement stmt = null ;
36 try {
37 //獲取Connection 對象
38 conn = ds.getConnection() ;
39 stmt = conn.prepareStatement(sql) ;
40
41 // 獲取ParameterMetaData 元數(shù)據(jù)對象。
42 ParameterMetaData pmd = stmt.getParameterMetaData() ;
43
44 //獲取SQL語句中需要設(shè)置的參數(shù)的個數(shù)
45 int parameterCount = pmd.getParameterCount() ;
46 if (parameterCount 》 0) {
47 if (obj == null || obj.length != parameterCount) {
48 throw new MyJdbcFrameException( “parameterCount is error!”) ;
49 }
50 //設(shè)置參數(shù):
51 for ( int i = 0 ; i 《 obj.length ; i++) {
52 stmt.setObject(i+1, obj[i]) ;
53 }
54 }
55 //執(zhí)行語句:
56 stmt.executeUpdate() ;
57
58 } catch(Exception e ) {
59 throw new MyJdbcFrameException(e.getMessage()) ;
60 } finally {
61 release(stmt, null, conn) ;
62 }
63 }
64
65 public Object query(String sql , Object[] obj , ResultSetHandler rsh) {
66 Connection conn = null ;
67 PreparedStatement stmt = null ;
68 ResultSet rs = null ;
69 try {
70 //獲取Connection 對象
71 conn = ds.getConnection() ;
72 stmt = conn.prepareStatement(sql) ;
73
74 // 獲取ParameterMetaData 元數(shù)據(jù)對象。
75 ParameterMetaData pmd = stmt.getParameterMetaData() ;
76
77 //獲取SQL語句中需要設(shè)置的參數(shù)的個數(shù)
78 int parameterCount = pmd.getParameterCount() ;
79
80 if (obj.length != parameterCount) {
81 throw new MyJdbcFrameException( “‘” +sql +“’ : parameterCount is error!”) ;
82 }
83 //設(shè)置參數(shù):
84 for ( int i = 0 ; i 《 obj.length ; i++) {
85 stmt.setObject(i+1, obj[i]) ;
86 }
87 //執(zhí)行語句:
88 rs = stmt.executeQuery();
89
90 return rsh.handler(rs);
91 } catch(Exception e ) {
92 throw new MyJdbcFrameException(e.getMessage()) ;
93 } finally {
94 release(stmt, null, conn) ;
95 }
96 }
97 /**
98 * 釋放資源
99 * @param stmt
100 * @param rs
101 * @param conn
102 */
103 public static void release(Statement stmt
104 , ResultSet rs
105 , Connection conn) {
106 if(rs != null) {
107 try {
108 rs.close() ;
109 } catch (SQLException e) {
110 e.printStackTrace();
111 }
112 rs = null ;
113 }
114 if (stmt != null) {
115 try {
116 stmt.close();
117 } catch (SQLException e) {
118 e.printStackTrace();
119 }
120 stmt = null ;
121 }
122 if (conn != null) {
123 try {
124 conn.close();
125 } catch (SQLException e) {
126 e.printStackTrace();
127 }
128 conn = null ;
129 }
130 }
131
132 }
2、接口:策略模式的接口:ResultSetHandler 。
1 import java.sql.ResultSet;
2
3 //抽象策略模式
4 public interface ResultSetHandler {
5 public Object handler(ResultSet rs) ;
6 }
這里對ResultSetHandler 接口實現(xiàn)一個BeanHandler 實例 :
1 import java.lang.reflect.Field;
2 import java.sql.ResultSet;
3 import java.sql.ResultSetMetaData;
4
5 /**
6 * 該類獲取ResultSet 結(jié)果集中的第一個值,封裝到JavaBean中
7 * @author 賀佐安
8 *
9 */
10 public class BeanHandler implements ResultSetHandler {
11 //獲取要封裝的JavaBean的字節(jié)碼
12 private Class clazz ;
13 public BeanHandler (Class clazz) {
14 this.clazz = clazz ;
15 }
16
17 public Object handler(ResultSet rs) {
18 try {
19 if (rs.next()) {
20 //1、獲取結(jié)果集的元數(shù)據(jù)。
21 ResultSetMetaData rsm = rs.getMetaData() ;
22 //2、創(chuàng)建JavaBean的實例:
23 Object obj = clazz.newInstance() ;
24 //3、將數(shù)據(jù)封裝到JavaBean中。
25 for (int i = 0 ; i 《 rsm.getColumnCount() ; i ++) {
26 //獲取屬性名
27 String columnName = rsm.getColumnName(i+1) ;
28 //獲取屬性值
29 Object value = rs.getObject(i+1) ;
30
31 Field objField = obj.getClass().getDeclaredField(columnName) ;
32 objField.setAccessible(true) ;
33 objField.set(obj, value) ;
34 }
35 return obj ;
36 } else {
37 return null ;
38 }
39 } catch (Exception e) {
40 throw new RuntimeException(e) ;
41 }
42 }
43 }
3、自定義異常類:繼承RuntimeException。如:
1 public class MyJdbcFrameException extends RuntimeException {
2 public MyJdbcFrameException() {
3 super() ;
4 }
5 public MyJdbcFrameException(String e) {
6 super(e) ;
7 }
8 }
然后就可以將其打包發(fā)布,在以后寫數(shù)據(jù)庫操作時就可以用自己的JDBC框架了,如果要完成查詢多條語句什么的,則要實現(xiàn)ResultSetHandler 接口。來完成更多的功能。
評論
查看更多