JDBC是一種用于執(zhí)行SQL語(yǔ)句的Java API,可以為多種關(guān)系數(shù)據(jù)庫(kù)提供統(tǒng)一訪問(wèn),它由一組用Java語(yǔ)言編寫(xiě)的類(lèi)和接口組成。JDBC提供了一種基準(zhǔn),據(jù)此可以構(gòu)建更高級(jí)的工具和接口,使數(shù)據(jù)庫(kù)開(kāi)發(fā)人員能夠編寫(xiě)數(shù)據(jù)庫(kù)應(yīng)用程序,同時(shí),JDBC也是個(gè)商標(biāo)名。
有了JDBC,向各種關(guān)系數(shù)據(jù)發(fā)送SQL語(yǔ)句就是一件很容易的事。換言之,有了JDBC API,就不必為訪問(wèn)Sybase數(shù)據(jù)庫(kù)專(zhuān)門(mén)寫(xiě)一個(gè)程序,為訪問(wèn)Oracle數(shù)據(jù)庫(kù)又專(zhuān)門(mén)寫(xiě)一個(gè)程序,或?yàn)樵L問(wèn)Informix數(shù)據(jù)庫(kù)又編寫(xiě)另一個(gè)程序等等,程序員只需用JDBC API寫(xiě)一個(gè)程序就夠了,它可向相應(yīng)數(shù)據(jù)庫(kù)發(fā)送SQL調(diào)用。同時(shí),將Java語(yǔ)言和JDBC結(jié)合起來(lái)使程序員不必為不同的平臺(tái)編寫(xiě)不同的應(yīng)用程序,只須寫(xiě)一遍程序就可以讓它在任何平臺(tái)上運(yùn)行,這也是Java語(yǔ)言“編寫(xiě)一次,處處運(yùn)行”的優(yōu)勢(shì)。
Java數(shù)據(jù)庫(kù)連接體系結(jié)構(gòu)是用于Java應(yīng)用程序連接數(shù)據(jù)庫(kù)的標(biāo)準(zhǔn)方法。JDBC對(duì)Java程序員而言是API,對(duì)實(shí)現(xiàn)與數(shù)據(jù)庫(kù)連接的服務(wù)提供商而言是接口模型。作為API,JDBC為程序開(kāi)發(fā)提供標(biāo)準(zhǔn)的接口,并為數(shù)據(jù)庫(kù)廠商及第三方中間件廠商實(shí)現(xiàn)與數(shù)據(jù)庫(kù)的連接提供了標(biāo)準(zhǔn)方法。JDBC使用已有的SQL標(biāo)準(zhǔn)并支持與其它數(shù)據(jù)庫(kù)連接標(biāo)準(zhǔn),如ODBC之間的橋接。JDBC實(shí)現(xiàn)了所有這些面向標(biāo)準(zhǔn)的目標(biāo)并且具有簡(jiǎn)單、嚴(yán)格類(lèi)型定義且高性能實(shí)現(xiàn)的接口。
Java 具有堅(jiān)固、安全、易于使用、易于理解和可從網(wǎng)絡(luò)上自動(dòng)下載等特性,是編寫(xiě)數(shù)據(jù)庫(kù)應(yīng)用程序的杰出語(yǔ)言。所需要的只是 Java應(yīng)用程序與各種不同數(shù)據(jù)庫(kù)之間進(jìn)行對(duì)話的方法。而 JDBC 正是作為此種用途的機(jī)制。
JDBC 擴(kuò)展了 Java 的功能。例如,用 Java 和 JDBC API 可以發(fā)布含有 applet 的網(wǎng)頁(yè),而該 applet 使用的信息可能來(lái)自遠(yuǎn)程數(shù)據(jù)庫(kù)。企業(yè)也可以用 JDBC 通過(guò) Intranet 將所有職員連到一個(gè)或多個(gè)內(nèi)部數(shù)據(jù)庫(kù)中(即使這些職員所用的計(jì)算機(jī)有 Windows、 Macintosh 和UNIX 等各種不同的操作系統(tǒng))。隨著越來(lái)越多的程序員開(kāi)始使用Java 編程語(yǔ)言,對(duì)從 Java 中便捷地訪問(wèn)數(shù)據(jù)庫(kù)的要求也在日益增加。
MIS管理員們都喜歡 Java 和 JDBC 的結(jié)合,因?yàn)樗剐畔鞑プ兊萌菀缀徒?jīng)濟(jì)。企業(yè)可繼續(xù)使用它們安裝好的數(shù)據(jù)庫(kù),并能便捷地存取信息,即使這些信息是儲(chǔ)存在不同數(shù)據(jù)庫(kù)管理系統(tǒng)上。新程序的開(kāi)發(fā)期很短。安裝和版本控制將大為簡(jiǎn)化。程序員可只編寫(xiě)一遍應(yīng)用程序或只更新一次,然后將它放到服務(wù)器上,隨后任何人就都可得到最新版本的應(yīng)用程序。對(duì)于商務(wù)上的銷(xiāo)售信息服務(wù), Java 和JDBC 可為外部客戶提供獲取信息更新的更好方法。
一、數(shù)據(jù)庫(kù)連接池:
在一般用JDBC 進(jìn)行連接數(shù)據(jù)庫(kù)進(jìn)行CRUD操作時(shí),每一次都會(huì):
通過(guò):java.sql.Connection conn = DriverManager.getConnection(url,user,password); 重新獲取一個(gè)數(shù)據(jù)庫(kù)的鏈接再進(jìn)行操作,這樣用戶每次請(qǐng)求都需要向數(shù)據(jù)庫(kù)獲得鏈接,而數(shù)據(jù)庫(kù)創(chuàng)建連接通常需要消耗相對(duì)較大的資源,創(chuàng)建時(shí)間也較長(zhǎng)。
所以為了減少服務(wù)器的壓力,便可用連接池的方法:在啟動(dòng)Web應(yīng)用時(shí),數(shù)據(jù)就創(chuàng)建好一定數(shù)量的Connection鏈接
存放到一個(gè)容器中,然后當(dāng)用戶請(qǐng)求時(shí),服務(wù)器則向容器中獲取Connection鏈接來(lái)處理用戶的請(qǐng)求,當(dāng)用戶的請(qǐng)求完成后,
又將該Connection 鏈接放回到該容器中。這樣的一個(gè)容器稱(chēng)為連接池。
編寫(xiě)一個(gè)基本的連接池實(shí)現(xiàn)連接復(fù)用
步驟:
1、建立一個(gè)數(shù)據(jù)庫(kù)連接池容器。(因?yàn)榉奖愦嫒。瑒t使用LinkedList集合)
2、初始化一定數(shù)量的連接,放入到容器中。
3、等待用戶獲取連接對(duì)象。(該部分要加鎖)
|---記得刪除容器中對(duì)應(yīng)的對(duì)象,放置別人同時(shí)獲取到同一個(gè)對(duì)象。
4、提供一個(gè)方法,回收用戶用完的連接對(duì)象。
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 * 一個(gè)基本的數(shù)據(jù)連接池:
11 * 1、初始化時(shí)就建立一個(gè)容器,來(lái)存儲(chǔ)一定數(shù)量的Connection 對(duì)象
12 * 2、用戶通過(guò)調(diào)用MyDataSource 的getConnection 來(lái)獲取Connection 對(duì)象。
13 * 3、再通過(guò)release 方法來(lái)回收Connection 對(duì)象,而不是直接關(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 // 注冊(cè)數(shù)據(jù)庫(kù)驅(qū)動(dòng)
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 // 回收連接對(duì)象。
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ù)庫(kù)時(shí),則可以直接使用連接池中Connection 的對(duì)象。測(cè)試如下:
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ù)庫(kù)連接池中的所有連接。
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+“被獲取;連接池還有:”+mds.getLength());
22 mds.release(conn) ;
23 }
24 } catch (SQLException e) {
25 e.printStackTrace();
26 }
27 }
28 }
再運(yùn)行的時(shí)候,可以發(fā)現(xiàn),循環(huán)10次后,又再一次獲取到了第一次循環(huán)的得到的Connection對(duì)象。所以,這樣可以大大的減輕數(shù)據(jù)庫(kù)的壓力。上面只是一個(gè)簡(jiǎn)單的數(shù)據(jù)庫(kù)連接池,不完美的便是,回收需要調(diào)用數(shù)據(jù)池的release() 方法來(lái)進(jìn)行回收,那么可以不可以直接調(diào)用Connection 實(shí)例的close 便完成Connection 對(duì)象的回收呢?
二、數(shù)據(jù)源:
》 編寫(xiě)連接池需實(shí)現(xiàn)javax.sql.DataSource接口。
》 實(shí)現(xiàn)DataSource接口,并實(shí)現(xiàn)連接池功能的步驟:
1、在DataSource構(gòu)造函數(shù)中批量創(chuàng)建與數(shù)據(jù)庫(kù)的連接,并把創(chuàng)建的連接加入LinkedList對(duì)象中。
2、實(shí)現(xiàn)getConnection方法,讓getConnection方法每次調(diào)用時(shí),從LinkedList中取一個(gè)Connection返回給用戶。當(dāng)用戶使用完Connection,調(diào)用Connection.close()方法時(shí),Collection對(duì)象應(yīng)保證將自己返回到LinkedList中,而不要把conn還給數(shù)據(jù)庫(kù)。
利用動(dòng)態(tài)代理和包裝設(shè)計(jì)模式來(lái)標(biāo)準(zhǔn)的數(shù)據(jù)源。
1、包裝設(shè)計(jì)模式實(shí)現(xiàn)標(biāo)準(zhǔn)數(shù)據(jù)源:
這里的用包裝設(shè)計(jì)模式,便是將Connection 接口進(jìn)行包裝。簡(jiǎn)單總結(jié)一下包裝設(shè)計(jì)模式的步驟:
a)定義一個(gè)類(lèi),實(shí)現(xiàn)與被包裝類(lèi)()相同的接口。
|----可以先自己寫(xiě)一個(gè)適配器,然后后面繼承這個(gè)適配器,改寫(xiě)需要改寫(xiě)的方法,提高編程效率。
b)定義一個(gè)實(shí)例變量,記住被包裝類(lèi)的對(duì)象的引用。
c)定義構(gòu)造方法,轉(zhuǎn)入被包裝類(lèi)的對(duì)象。
e)對(duì)需要改寫(xiě)的方法,改寫(xiě)。
f)對(duì)不需要改寫(xiě)的方法,調(diào)用原來(lái)被包裝類(lèi)的對(duì)應(yīng)方法。
所以先編寫(xiě)一個(gè)類(lèi)似適配器的類(lèi),將Connection 接口的方法都進(jìn)行實(shí)現(xiàn):
View Code
然后再對(duì)Connection 接口進(jìn)行包裝,將close 方法修改掉:
1 import java.sql.Connection;
2 import java.sql.SQLException;
3 import java.util.LinkedList;
4 /**
5 * 對(duì)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ě)要實(shí)現(xiàn)的方法
18 public void close() throws SQLException {
19 pool.addLast(conn) ;
20 }
21 }
編寫(xiě)標(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 * 編寫(xiě)標(biāo)準(zhǔn)的數(shù)據(jù)源:
13 * 1、實(shí)現(xiàn)DataSource 接口
14 * 2、獲取在實(shí)現(xiàn)類(lèi)的構(gòu)造方法中批量獲取Connection 對(duì)象,并將這些Connection 存儲(chǔ)
15 * 在LinkedList 容器中。
16 * 3、實(shí)現(xiàn)getConnection() 方法,調(diào)用時(shí)返回LinkedList容器的Connection對(duì)象給用戶。
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 // 注冊(cè)數(shù)據(jù)庫(kù)驅(qū)動(dòng)
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 //、從連接池獲取連接:通過(guò)包裝模式
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 // 回收連接對(duì)象。
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、動(dòng)態(tài)代理實(shí)現(xiàn)標(biāo)準(zhǔn)數(shù)據(jù)源:
相對(duì)于用包裝設(shè)計(jì)來(lái)完成標(biāo)準(zhǔn)數(shù)據(jù)源,用動(dòng)態(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 * 編寫(xiě)標(biāo)準(zhǔn)的數(shù)據(jù)源:
16 * 1、實(shí)現(xiàn)DataSource 接口
17 * 2、獲取在實(shí)現(xiàn)類(lèi)的構(gòu)造方法中批量獲取Connection 對(duì)象,并將這些Connection 存儲(chǔ)
18 * 在LinkedList 容器中。
19 * 3、實(shí)現(xiàn)getConnection() 方法,調(diào)用時(shí)返回LinkedList容器的Connection對(duì)象給用戶。
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 // 注冊(cè)數(shù)據(jù)庫(kù)驅(qū)動(dòng)
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 //、從連接池獲取連接:通過(guò)動(dòng)態(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è)計(jì)模式:
60 @Override
61 public Object invoke(Object proxy, Method method, Object[] args)
62 throws Throwable {
63 if(“close”.equals(method.getName())){
64 //誰(shuí)調(diào)用,
65 return pool.add(conn);//當(dāng)調(diào)用close方法時(shí),攔截了,把鏈接放回池中了
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)然覺(jué)得麻煩的則可以直接使用一些開(kāi)源的數(shù)據(jù)源如:DBCP、C3P0等。DBCP的原理是用包裝設(shè)計(jì)模式開(kāi)發(fā)的數(shù)據(jù)源,而C3P0則是動(dòng)態(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 工具類(lèi)
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 //通過(guò)BasicDataSourceFactory 的creatDataSurce 方法創(chuàng)建 BasicDataSource 對(duì)象。
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 開(kāi)源數(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 }
使用這兩個(gè)數(shù)據(jù)源時(shí),直接調(diào)用獲取到的Connection 連接的close 方法,也是將連接放到pool中去。
三、元數(shù)據(jù)(DatabaseMetaData)信息的獲取
》 元數(shù)據(jù):數(shù)據(jù)庫(kù)、表、列的定義信息。
》 元數(shù)據(jù)信息的獲?。簽榱司帉?xiě)JDBC框架使用。
1、數(shù)據(jù)庫(kù)本身信息的獲取:java.sql.DataBaseMateData java.sql.Connection.getMetaData() ;
DataBaseMateData 實(shí)現(xiàn)類(lèi)的常用方法:
getURL():返回一個(gè)String類(lèi)對(duì)象,代表數(shù)據(jù)庫(kù)的URL。
getUserName():返回連接當(dāng)前數(shù)據(jù)庫(kù)管理系統(tǒng)的用戶名。
getDatabaseProductName():返回?cái)?shù)據(jù)庫(kù)的產(chǎn)品名稱(chēng)。
getDatabaseProductVersion():返回?cái)?shù)據(jù)庫(kù)的版本號(hào)。
getDriverName():返回驅(qū)動(dòng)驅(qū)動(dòng)程序的名稱(chēng)。
getDriverVersion():返回驅(qū)動(dòng)程序的版本號(hào)。
isReadOnly():返回一個(gè)boolean值,指示數(shù)據(jù)庫(kù)是否只允許讀操作。
2、ParameterMetaData: 代表PerparedStatment 中的SQL 參數(shù)元數(shù)據(jù)信息: java.sql.ParameterMetaData java.sql.PerparedStatement.getParameterMetaData() ;
ParameterMetaData 實(shí)現(xiàn)類(lèi)常用方法:
getParameterCount() :獲得指定參數(shù)的個(gè)數(shù)
getParameterType(int param) :獲得指定參數(shù)的sql類(lèi)型(驅(qū)動(dòng)可能不支持)
3、ResultSetMetaData : 代表結(jié)果集的源數(shù)據(jù)信息:相當(dāng)于SQL 中的 :DESC java.sql.ResultSetMetaData java.sql.ResultSet.getMetaData() ;
java.sql.ResultSetMetaData 接口中常用的方法:
a) getColumnCount() : 獲取查詢(xún)方法有幾列。
b) getColumnName(int index) : 獲取列名:index從1開(kāi)始。
c) getColumnType(int index) : 獲取列的數(shù)據(jù)類(lèi)型。返回的是TYPES 中的常量值。
四、編寫(xiě)自己的JDBC框架:
JDBC框架的基本組成:
1、核心類(lèi):
a、定義一個(gè)指定javax.sql.DataSource 實(shí)例的引用變量,通過(guò)構(gòu)造函數(shù)獲取指定的實(shí)例并給定義的變量。
b、編寫(xiě)SQL運(yùn)行框架。
DML 語(yǔ)句的編寫(xiě):
1、通過(guò)獲取的javax.sql.DataSource 實(shí)例,獲取Connection 對(duì)象。
2、通過(guò)ParamenterMeteData 獲取數(shù)據(jù)庫(kù)元數(shù)據(jù)。
DQL 語(yǔ)句的編寫(xiě):
1、通過(guò)獲取的DataSource 實(shí)例,獲取Connection 對(duì)象。
2、通過(guò)ParamenterMeteData、ResultSetMetaData 等獲取數(shù)據(jù)庫(kù)元數(shù)據(jù)。
3、用抽象策略設(shè)計(jì)模式:設(shè)計(jì)一個(gè)ResultSetHandler 接口,作用:將查找出的數(shù)據(jù)封裝到指定的JavaBean中。
|————這里的JavaBean,由用戶來(lái)指定。
抽象策略模式,用戶可以更具具體的功能來(lái)擴(kuò)展成具體策略設(shè)計(jì)模式。如:查找的一條信息、查找的所有信息。
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 * 實(shí)現(xiàn)JDBC 框架的核心類(lèi)。
12 * 在該類(lèi)中定義了SQL語(yǔ)句完成的方法;
13 * @author 賀佐安
14 *
15 */
16 public class MyJdbcFrame {
17 /**
18 * javax.sql.DataSource 實(shí)例的引用變量
19 */
20 private DataSource ds = null ;
21 /**
22 * 將用戶指定的DataSource 指定給系統(tǒng)定義的DataSource 實(shí)例的引用變量
23 * @param ds
24 */
25 public MyJdbcFrame(DataSource ds ) {
26 this.ds = ds ;
27 }
28 /**
29 * 執(zhí)行UPDATE、DELETE、INSERT 語(yǔ)句。
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 對(duì)象
38 conn = ds.getConnection() ;
39 stmt = conn.prepareStatement(sql) ;
40
41 // 獲取ParameterMetaData 元數(shù)據(jù)對(duì)象。
42 ParameterMetaData pmd = stmt.getParameterMetaData() ;
43
44 //獲取SQL語(yǔ)句中需要設(shè)置的參數(shù)的個(gè)數(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í)行語(yǔ)句:
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 對(duì)象
71 conn = ds.getConnection() ;
72 stmt = conn.prepareStatement(sql) ;
73
74 // 獲取ParameterMetaData 元數(shù)據(jù)對(duì)象。
75 ParameterMetaData pmd = stmt.getParameterMetaData() ;
76
77 //獲取SQL語(yǔ)句中需要設(shè)置的參數(shù)的個(gè)數(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í)行語(yǔ)句:
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 }
這里對(duì)ResultSetHandler 接口實(shí)現(xiàn)一個(gè)BeanHandler 實(shí)例 :
1 import java.lang.reflect.Field;
2 import java.sql.ResultSet;
3 import java.sql.ResultSetMetaData;
4
5 /**
6 * 該類(lèi)獲取ResultSet 結(jié)果集中的第一個(gè)值,封裝到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的實(shí)例:
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、自定義異常類(lèi):繼承RuntimeException。如:
1 public class MyJdbcFrameException extends RuntimeException {
2 public MyJdbcFrameException() {
3 super() ;
4 }
5 public MyJdbcFrameException(String e) {
6 super(e) ;
7 }
8 }
然后就可以將其打包發(fā)布,在以后寫(xiě)數(shù)據(jù)庫(kù)操作時(shí)就可以用自己的JDBC框架了,如果要完成查詢(xún)多條語(yǔ)句什么的,則要實(shí)現(xiàn)ResultSetHandler 接口。來(lái)完成更多的功能。
評(píng)論
查看更多