1-JDBC概述
序言:數(shù)據(jù)持久化
持久化(persistence):把數(shù)據(jù)保存到可掉電式存儲(chǔ)設(shè)備中以供之后使用。大多數(shù)情況下,特別是企業(yè)級(jí)應(yīng)用,數(shù)據(jù)持久化意味著將內(nèi)存中的數(shù)據(jù)保存到硬盤上加以”固化”,而持久化的實(shí)現(xiàn)過(guò)程大多通過(guò)各種關(guān)系數(shù)據(jù)庫(kù)來(lái)完成。
持久化的主要應(yīng)用是將內(nèi)存中的數(shù)據(jù)存儲(chǔ)在關(guān)系型數(shù)據(jù)庫(kù)中,當(dāng)然也可以存儲(chǔ)在磁盤文件、xml數(shù)據(jù)文件中。?
Java 中的數(shù)據(jù)存儲(chǔ)技術(shù)
在Java中,數(shù)據(jù)庫(kù)存取技術(shù)可分為如下幾類:
JDBC直接訪問(wèn)數(shù)據(jù)庫(kù)
JDO技術(shù)
第三方O/R工具,如Hibernate, ibatis 等
JDBC是java訪問(wèn)數(shù)據(jù)庫(kù)的基石,JDO, Hibernate等只是更好的封裝了JDBC。
JDBC基礎(chǔ)
JDBC(Java Database Connectivity)是一個(gè)獨(dú)立于特定數(shù)據(jù)庫(kù)管理系統(tǒng)、通用的SQL數(shù)據(jù)庫(kù)存取和操作的公共接口(一組API),定義了用來(lái)訪問(wèn)數(shù)據(jù)庫(kù)的標(biāo)準(zhǔn)Java類庫(kù)(java.sql,javax.sql)使用這個(gè)類庫(kù)可以以一種標(biāo)準(zhǔn)的方法、方便地訪問(wèn)數(shù)據(jù)庫(kù)資源JDBC為訪問(wèn)不同的數(shù)據(jù)庫(kù)提供了一種統(tǒng)一的途徑,為開(kāi)發(fā)者屏蔽了一些細(xì)節(jié)問(wèn)題。
JDBC的目標(biāo)是使Java程序員使用JDBC可以連接任何提供了JDBC驅(qū)動(dòng)程序的數(shù)據(jù)庫(kù)系統(tǒng),這樣就使得程序員無(wú)需對(duì)特定的數(shù)據(jù)庫(kù)系統(tǒng)的特點(diǎn)有過(guò)多的了解,從而大大簡(jiǎn)化和加快了開(kāi)發(fā)過(guò)程。
JDBC體系結(jié)構(gòu)
JDBC接口(API)包括兩個(gè)層次:?
面向應(yīng)用的API:Java API,抽象接口,供應(yīng)用程序開(kāi)發(fā)人員使用(連接數(shù)據(jù)庫(kù),執(zhí)行SQL語(yǔ)句,獲得結(jié)果)。?
面向數(shù)據(jù)庫(kù)的API:Java Driver API,供開(kāi)發(fā)商開(kāi)發(fā)數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序用。
JDBC是sun公司提供一套用于數(shù)據(jù)庫(kù)操作的接口,java程序員只需要面向這套接口編程即可。不同的數(shù)據(jù)庫(kù)廠商,需要針對(duì)這套接口,提供不同實(shí)現(xiàn)。不同的實(shí)現(xiàn)的集合,即為不同數(shù)據(jù)庫(kù)的驅(qū)動(dòng)。————面向接口編程
JDBC驅(qū)動(dòng)程序分類。
JDBC驅(qū)動(dòng)程序:各個(gè)數(shù)據(jù)庫(kù)廠商根據(jù)JDBC的規(guī)范制作的 JDBC 實(shí)現(xiàn)類的類庫(kù) ?
JDBC驅(qū)動(dòng)程序總共有四種類型:
第一類:JDBC-ODBC橋。?
第二類:部分本地API部分Java的驅(qū)動(dòng)程序。?
第三類:JDBC網(wǎng)絡(luò)純Java驅(qū)動(dòng)程序。?
第四類:本地協(xié)議的純 Java 驅(qū)動(dòng)程序。?
第三、四兩類都是純Java的驅(qū)動(dòng)程序,因此,對(duì)于Java開(kāi)發(fā)者來(lái)說(shuō),它們?cè)谛阅堋⒖梢浦残浴⒐δ艿确矫娑加袃?yōu)勢(shì)。
第一類:ODBC ?
早期對(duì)數(shù)據(jù)庫(kù)的訪問(wèn),都是調(diào)用數(shù)據(jù)庫(kù)廠商提供的專有的 API。為了在 Windows 平臺(tái)下提供統(tǒng)一的訪問(wèn)方式,微軟推出了 ODBC(Open Database Connectivity,開(kāi)放式數(shù)據(jù)庫(kù)連接),并提供了 ODBC API,使用者在程序中只需要調(diào)用 ODBC API,由 ODBC 驅(qū)動(dòng)程序?qū)⒄{(diào)用轉(zhuǎn)換成為對(duì)特定的數(shù)據(jù)庫(kù)的調(diào)用請(qǐng)求一個(gè)基于ODBC的應(yīng)用程序?qū)?shù)據(jù)庫(kù)的操作不依賴任何DBMS(database manager system),不直接與DBMS打交道,所有的數(shù)據(jù)庫(kù)操作由對(duì)應(yīng)的DBMS的ODBC驅(qū)動(dòng)程序完成。也就是說(shuō),不論是FoxPro、Access ,MYSQL還是Oracle數(shù)據(jù)庫(kù),均可用ODBC API進(jìn)行訪問(wèn)。由此可見(jiàn),ODBC的最大優(yōu)點(diǎn)是能以統(tǒng)一的方式處理所有的數(shù)據(jù)庫(kù)。
JDBC-ODBC橋?
JDBC-ODBC 橋本身也是一個(gè)驅(qū)動(dòng),利用這個(gè)驅(qū)動(dòng),可以使用 JDBC-API 通過(guò)ODBC 去訪問(wèn)數(shù)據(jù)庫(kù)。這種機(jī)制實(shí)際上是把標(biāo)準(zhǔn)的 JDBC 調(diào)用轉(zhuǎn)換成相應(yīng)的 ODBC 調(diào)用,并通過(guò) ODBC 訪問(wèn)數(shù)據(jù)庫(kù)因?yàn)樾枰ㄟ^(guò)多層調(diào)用,所以利用 JDBC-ODBC 橋訪問(wèn)數(shù)據(jù)庫(kù)的效率較低在?JDK 中,提供了 JDBC-ODBC 橋的實(shí)現(xiàn)類(sun.jdbc.odbc.JdbcOdbcDriver)。
第二類:部分本地API部分Java的驅(qū)動(dòng)程序
這種類型的 JDBC 驅(qū)動(dòng)程序使用 Java 編寫(xiě),它調(diào)用數(shù)據(jù)庫(kù)廠商提供的本地 API通過(guò)這種類型的 JDBC 驅(qū)動(dòng)程序訪問(wèn)數(shù)據(jù)庫(kù)減少了 ODBC 的調(diào)用環(huán)節(jié),提高了數(shù)據(jù)庫(kù)訪問(wèn)的效率在這種方式下需要在客戶的機(jī)器上安裝本地 JDBC 驅(qū)動(dòng)程序和特定廠商的本地 API 。
第三類:JDBC網(wǎng)絡(luò)純Java驅(qū)動(dòng)程序
這種驅(qū)動(dòng)利用中間件的應(yīng)用服務(wù)器來(lái)訪問(wèn)數(shù)據(jù)庫(kù)。應(yīng)用服務(wù)器作為一個(gè)到多個(gè)數(shù)據(jù)庫(kù)的網(wǎng)關(guān),客戶端通過(guò)它可以連接到不同的數(shù)據(jù)庫(kù)服務(wù)器。
應(yīng)用服務(wù)器通常有自己的網(wǎng)絡(luò)協(xié)議,Java 用戶程序通過(guò) JDBC 驅(qū)動(dòng)程序?qū)?JDBC 調(diào)用發(fā)送給應(yīng)用服務(wù)器,應(yīng)用服務(wù)器使用本地程序驅(qū)動(dòng)訪問(wèn)數(shù)據(jù)庫(kù),從而完成請(qǐng)求。
第四類:本地協(xié)議的純 Java 驅(qū)動(dòng)程序
多數(shù)數(shù)據(jù)庫(kù)廠商已經(jīng)支持允許客戶程序通過(guò)網(wǎng)絡(luò)直接與數(shù)據(jù)庫(kù)通信的網(wǎng)絡(luò)協(xié)議。
這種類型的驅(qū)動(dòng)程序完全使用 Java 編寫(xiě),通過(guò)與數(shù)據(jù)庫(kù)建立的 Socket 連接,采用具體與廠商的網(wǎng)絡(luò)協(xié)議把 JDBC 調(diào)用轉(zhuǎn)換為直接連接的網(wǎng)絡(luò)調(diào)用JDBC API。
JDBC API 是一系列的接口,它使得應(yīng)用程序能夠進(jìn)行數(shù)據(jù)庫(kù)聯(lián)接,執(zhí)行SQL語(yǔ)句,并且得到返回結(jié)果。
2-獲取數(shù)據(jù)庫(kù)連接
Driver 接口
java.sql.Driver 接口是所有 JDBC 驅(qū)動(dòng)程序需要實(shí)現(xiàn)的接口。這個(gè)接口是提供給數(shù)據(jù)庫(kù)廠商使用的,不同數(shù)據(jù)庫(kù)廠商提供不同的實(shí)現(xiàn)在程序中不需要直接去訪問(wèn)實(shí)現(xiàn)了 Driver 接口的類,而是由驅(qū)動(dòng)程序管理器類(java.sql.DriverManager)去調(diào)用這些Driver實(shí)現(xiàn)。
Oracle的驅(qū)動(dòng):oracle.jdbc.driver.OracleDriver
mySql的驅(qū)動(dòng): com.mysql.jdbc.Driver
加載與注冊(cè) JDBC 驅(qū)動(dòng)
方式一:加載 JDBC 驅(qū)動(dòng)需調(diào)用 Class 類的靜態(tài)方法 forName(),向其傳遞要加載的 JDBC 驅(qū)動(dòng)的類名
Class.forName(“com.mysql.jdbc.Driver”);
方式二:DriverManager 類是驅(qū)動(dòng)程序管理器類,負(fù)責(zé)管理驅(qū)動(dòng)程序
DriverManager.registerDriver(com.mysql.jdbc.Driver);
通常不用顯式調(diào)用 DriverManager 類的 registerDriver() 方法來(lái)注冊(cè)驅(qū)動(dòng)程序類的實(shí)例,因?yàn)?Driver 接口的驅(qū)動(dòng)程序類都包含了靜態(tài)代碼塊,在這個(gè)靜態(tài)代碼塊中,會(huì)調(diào)用 DriverManager.registerDriver() 方法來(lái)注冊(cè)自身的一個(gè)實(shí)例。
建立連接(Connection)
可以調(diào)用 DriverManager 類的 getConnection() 方法建立到數(shù)據(jù)庫(kù)的連接。
User,password可以用“屬性名=屬性值”方式告訴數(shù)據(jù)庫(kù);
JDBC URL 用于標(biāo)識(shí)一個(gè)被注冊(cè)的驅(qū)動(dòng)程序,驅(qū)動(dòng)程序管理器通過(guò)這個(gè) URL 選擇正確的驅(qū)動(dòng)程序,從而建立到數(shù)據(jù)庫(kù)的連接。
JDBC URL的標(biāo)準(zhǔn)由三部分組成,各部分間用冒號(hào)分隔。?
jdbc:子協(xié)議:子名稱
協(xié)議:JDBC URL中的協(xié)議總是jdbc 。
子協(xié)議:子協(xié)議用于標(biāo)識(shí)一個(gè)數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序。
子名稱:一種標(biāo)識(shí)數(shù)據(jù)庫(kù)的方法。子名稱可以依不同的子協(xié)議而變化,用子名稱的目的是為了定位數(shù)據(jù)庫(kù)提供足夠的信息。包含主機(jī)名(對(duì)應(yīng)服務(wù)端的ip地址),端口號(hào),數(shù)據(jù)庫(kù)名。
幾種常用數(shù)據(jù)庫(kù)的JDBC URL
jdbc:mysql://localhost:3306/test?
協(xié)議 子協(xié)議 ? ? ? 子名稱
對(duì)于 Oracle 數(shù)據(jù)庫(kù)連接,采用如下形式:?
jdbc:oracle:thin:@localhost:1521:atguigu
對(duì)于 SQLServer 數(shù)據(jù)庫(kù)連接,采用如下形式:
jdbc:microsoft:sqlserver//localhost:1433; DatabaseName=sid
對(duì)于 MYSQL 數(shù)據(jù)庫(kù)連接,采用如下形式: ??
jdbc:mysql://localhost:3306/atguigu
Statement
一旦獲取了連接對(duì)象Connection, 還不可以執(zhí)行SQL, 必須要從Connection連接對(duì)象獲取執(zhí)行體對(duì)象Statement才能執(zhí)行SQL。
Connection?connection?=?getConnection(); Statement?state?=?connection.createStatement(); int?n?=?state.executeUpdate(“insert,update,delete…”);
其中n是執(zhí)行增刪改后對(duì)表產(chǎn)生的影響的記錄數(shù)如果執(zhí)行一個(gè)查詢則返回一個(gè)ResultSet結(jié)果集對(duì)象.
SQL 注入攻擊
SQL 注入是利用某些系統(tǒng)沒(méi)有對(duì)用戶輸入的數(shù)據(jù)進(jìn)行充分的檢查,而在用戶輸入數(shù)據(jù)中注入非法的 SQL 語(yǔ)句段或命令(如:SELECT user, password FROM user_table WHERE user=’a’ OR 1 = ‘ AND password = ‘ OR ‘1’ = ‘1’) ,從而利用系統(tǒng)的 SQL 引擎完成惡意行為的做法對(duì)于 Java 而言,要防范 SQL 注入,只要用 PreparedStatement(從Statement擴(kuò)展而來(lái)) 就可以了取代 Statement 。
3-使用PreparedStatement
數(shù)據(jù)類型轉(zhuǎn)換表
可以通過(guò)調(diào)用 Connection 對(duì)象的 preparedStatement() 方法獲取 PreparedStatement 對(duì)象。
PreparedStatement 接口是 Statement 的子接口,它表示一條預(yù)編譯過(guò)的 SQL 語(yǔ)句。
PreparedStatement 對(duì)象所代表的 SQL 語(yǔ)句中的參數(shù)用問(wèn)號(hào)(?)來(lái)表示,調(diào)用 PreparedStatement 對(duì)象的 setXxx() 方法來(lái)設(shè)置這些參數(shù). setXxx() 方法有兩個(gè)參數(shù),第一個(gè)參數(shù)是要設(shè)置的 SQL 語(yǔ)句中的參數(shù)的索引(從 1 開(kāi)始),第二個(gè)是設(shè)置的 SQL 語(yǔ)句中的參數(shù)的值。
PreparedStatement vs Statement
代碼的可讀性和可維護(hù)性.
PreparedStatement 能最大可能提高性能:
DBServer會(huì)對(duì)預(yù)編譯語(yǔ)句提供性能優(yōu)化。因?yàn)轭A(yù)編譯語(yǔ)句有可能被重復(fù)調(diào)用,所以語(yǔ)句在被DBServer的編譯器編譯后的執(zhí)行代碼被緩存下來(lái),那么下次調(diào)用時(shí)只要是相同的預(yù)編譯語(yǔ)句就不需要編譯,只要將參數(shù)直接傳入編譯過(guò)的語(yǔ)句執(zhí)行代碼中就會(huì)得到執(zhí)行。
在statement語(yǔ)句中,即使是相同操作但因?yàn)閿?shù)據(jù)內(nèi)容不一樣,所以整個(gè)語(yǔ)句本身不能匹配,沒(méi)有緩存語(yǔ)句的意義。事實(shí)是沒(méi)有數(shù)據(jù)庫(kù)會(huì)對(duì)普通語(yǔ)句編譯后的執(zhí)行代碼緩存.這樣每執(zhí)行一次都要對(duì)傳入的語(yǔ)句編譯一次。 ?(語(yǔ)法檢查,語(yǔ)義檢查,翻譯成二進(jìn)制命令,緩存)。
PreparedStatement 可以防止 SQL 注入?
連接數(shù)據(jù)庫(kù)、操作表的步驟:
注冊(cè)驅(qū)動(dòng) (只做一次)
建立連接(Connection)?
創(chuàng)建執(zhí)行SQL的語(yǔ)句(PreparedStatement )
執(zhí)行語(yǔ)句處
理執(zhí)行結(jié)果(ResultSet)
釋放資源
Connection?conn?=?null; PreparedStatement?st=null; ResultSet?rs?=?null; try?{??????? //獲得Connection?????? //創(chuàng)建PreparedStatement?????? //處理查詢結(jié)果ResultSet }catch(Exception?e){ ????? e.printStackTrance(); }?finally?{????? //釋放資源ResultSet,???????? //?PreparedStatement?,???? //Connection
釋放ResultSet, PreparedStatement ,Connection。
數(shù)據(jù)庫(kù)連接(Connection)是非常稀有的資源,用完后必須馬上釋放,如果Connection不能及時(shí)正確的關(guān)閉將導(dǎo)致系統(tǒng)宕機(jī)。Connection的使用原則是盡量晚創(chuàng)建,盡量早的釋放。
4-使用ResultSet、ResultSetMetaData操作數(shù)據(jù)表:SELECT
ORM:Object Relation Mapping
表 與 類 對(duì)應(yīng)
表的一行數(shù)據(jù) 與 類的一個(gè)對(duì)象對(duì)應(yīng)
表的一列 與類的一個(gè)屬性對(duì)應(yīng)
ResultSet
通過(guò)調(diào)用 PreparedStatement 對(duì)象的 excuteQuery() 方法創(chuàng)建該對(duì)象。
ResultSet 對(duì)象以邏輯表格的形式封裝了執(zhí)行數(shù)據(jù)庫(kù)操作的結(jié)果集,ResultSet 接口由數(shù)據(jù)庫(kù)廠商實(shí)現(xiàn)。
ResultSet 對(duì)象維護(hù)了一個(gè)指向當(dāng)前數(shù)據(jù)行的游標(biāo),初始的時(shí)候,游標(biāo)在第一行之前,可以通過(guò) ResultSet 對(duì)象的 next() 方法移動(dòng)到下一行。
ResultSet 接口的常用方法:
boolean next()
getString()
…
處理執(zhí)行結(jié)果(ResultSet)
讀取(查詢)對(duì)應(yīng)SQL的SELECT,返回查詢結(jié)果
st?=?conn.createStatement(); String?sql?=?"select?id,?name,?age,birth?from?user"; rs?=?st.executeQuery(sql); while?(rs.next())?{ System.out.print(rs.getInt("id")?+?"?t?"); System.out.print(rs.getString("name")?+?"?t"); System.out.print(rs.getInt("age")?+?"?t"); System.out.print(rs.getDate(“birth")?+?"?t?"); System.out.println();} }
關(guān)于Result的說(shuō)明
1. 查詢需要調(diào)用 Statement 的 executeQuery(sql) 方法,查詢結(jié)果是一個(gè) ResultSet 對(duì)象
2. 關(guān)于 ResultSet:代表結(jié)果集
ResultSet: 結(jié)果集. 封裝了使用 JDBC 進(jìn)行查詢的結(jié)果.?調(diào)用 Statement 對(duì)象的 executeQuery(sql) 可以得到結(jié)果集.
ResultSet 返回的實(shí)際上就是一張數(shù)據(jù)表. 有一個(gè)指針指向數(shù)據(jù)表的第一條記錄的前面.
3.可以調(diào)用 next() 方法檢測(cè)下一行是否有效. 若有效該方法返回 true, 且指針下移. 相當(dāng)于Iterator 對(duì)象的 hasNext() 和 next() 方法的結(jié)合體
4.當(dāng)指針指向一行時(shí), 可以通過(guò)調(diào)用 getXxx(int index) 或 getXxx(int columnName) 獲取每一列的值.?
例如: getInt(1), getString(“name”)
5.ResultSet 當(dāng)然也需要進(jìn)行關(guān)閉.?
MySQL BLOB 類型?
MySQL中,BLOB是一個(gè)二進(jìn)制大型對(duì)象,是一個(gè)可以存儲(chǔ)大量數(shù)據(jù)的容器,它能容納不同大小的數(shù)據(jù)。
MySQL的四種BLOB類型(除了在存儲(chǔ)的最大信息量上不同外,他們是等同的)。
實(shí)際使用中根據(jù)需要存入的數(shù)據(jù)大小定義不同的BLOB類型。
需要注意的是:如果存儲(chǔ)的文件過(guò)大,數(shù)據(jù)庫(kù)的性能會(huì)下降。
ResultSetMetaData 類
可用于獲取關(guān)于 ResultSet 對(duì)象中列的類型和屬性信息的對(duì)象。
ResultSetMetaData meta = rs.getMetaData();
getColumnName(int column):獲取指定列的名稱
getColumnLabel(int column):獲取指定列的別名
getColumnCount():返回當(dāng)前 ResultSet 對(duì)象中的列數(shù)。?
getColumnTypeName(int column):檢索指定列的數(shù)據(jù)庫(kù)特定的類型名稱。?
getColumnDisplaySize(int column):指示指定列的最大標(biāo)準(zhǔn)寬度,以字符為單位。?
isNullable(int column):指示指定列中的值是否可以為 null。 ?
isAutoIncrement(int column):指示是否自動(dòng)為指定列進(jìn)行編號(hào),這樣這些列仍然是只讀的。?
JDBC API 小結(jié)
java.sql.DriverManager用來(lái)裝載驅(qū)動(dòng)程序,獲取數(shù)據(jù)庫(kù)連接。
java.sql.Connection完成對(duì)某一指定數(shù)據(jù)庫(kù)的連接。
java.sql.Statement在一個(gè)給定的連接中作為SQL執(zhí)行聲明的容器,他包含了兩個(gè)重要的子類型。
Java.sql.PreparedSatement 用于執(zhí)行預(yù)編譯的sql聲明。
Java.sql.CallableStatement用于執(zhí)行數(shù)據(jù)庫(kù)中存儲(chǔ)過(guò)程的調(diào)用。
java.sql.ResultSet對(duì)于給定聲明取得結(jié)果的途徑。
兩種思想
面向接口編程的思想;
ORM思想:sql是需要結(jié)合列名和表的屬性名來(lái)寫(xiě),注意起別名。
兩種技術(shù)
JDBC元數(shù)據(jù):ResultSetMetaData;
PropertyUtils:通過(guò)Class.newInstance()創(chuàng)建一個(gè)對(duì)象,通過(guò)此類將查詢到的列值裝配給創(chuàng)建的對(duì)象。
5-批量處理
批量處理JDBC語(yǔ)句提高處理速度 。
當(dāng)需要成批插入或者更新記錄時(shí)。可以采用Java的批量更新機(jī)制,這一機(jī)制允許多條語(yǔ)句一次性提交給數(shù)據(jù)庫(kù)批量處理。通常情況下比單獨(dú)提交處理更有效率
JDBC的批量處理語(yǔ)句包括下面兩個(gè)方法:
addBatch(String):添加需要批量處理的SQL語(yǔ)句或是參數(shù);
executeBatch():執(zhí)行批量處理語(yǔ)句;clearBatch():清空緩存的數(shù)據(jù);
通常我們會(huì)遇到兩種批量執(zhí)行SQL語(yǔ)句的情況:
多條SQL語(yǔ)句的批量處理;
一個(gè)SQL語(yǔ)句的批量傳參;
6-數(shù)據(jù)庫(kù)連接池
JDBC數(shù)據(jù)庫(kù)連接池的必要性?
在使用開(kāi)發(fā)基于數(shù)據(jù)庫(kù)的web程序時(shí),傳統(tǒng)的模式基本是按以下步驟:
在主程序(如servlet、beans)中建立數(shù)據(jù)庫(kù)連接
進(jìn)行sql操作
斷開(kāi)數(shù)據(jù)庫(kù)連接
這種模式開(kāi)發(fā),存在的問(wèn)題:
普通的JDBC數(shù)據(jù)庫(kù)連接使用 DriverManager 來(lái)獲取,每次向數(shù)據(jù)庫(kù)建立連接的時(shí)候都要將 Connection 加載到內(nèi)存中,再驗(yàn)證用戶名和密碼(得花費(fèi)0.05s~1s的時(shí)間)。需要數(shù)據(jù)庫(kù)連接的時(shí)候,就向數(shù)據(jù)庫(kù)要求一個(gè),執(zhí)行完成后再斷開(kāi)連接。這樣的方式將會(huì)消耗大量的資源和時(shí)間。數(shù)據(jù)庫(kù)的連接資源并沒(méi)有得到很好的重復(fù)利用.若同時(shí)有幾百人甚至幾千人在線,頻繁的進(jìn)行數(shù)據(jù)庫(kù)連接操作將占用很多的系統(tǒng)資源,嚴(yán)重的甚至?xí)斐煞?wù)器的崩潰。對(duì)于每一次數(shù)據(jù)庫(kù)連接,使用完后都得斷開(kāi)。否則,如果程序出現(xiàn)異常而未能關(guān)閉,將會(huì)導(dǎo)致數(shù)據(jù)庫(kù)系統(tǒng)中的內(nèi)存泄漏,最終將導(dǎo)致重啟數(shù)據(jù)庫(kù)。這種開(kāi)發(fā)不能控制被創(chuàng)建的連接對(duì)象數(shù),系統(tǒng)資源會(huì)被毫無(wú)顧及的分配出去,如連接過(guò)多,也可能導(dǎo)致內(nèi)存泄漏,服務(wù)器崩潰。?
數(shù)據(jù)庫(kù)連接池(connection pool)?
為解決傳統(tǒng)開(kāi)發(fā)中的數(shù)據(jù)庫(kù)連接問(wèn)題,可以采用數(shù)據(jù)庫(kù)連接池技術(shù)。
數(shù)據(jù)庫(kù)連接池的基本思想就是為數(shù)據(jù)庫(kù)連接建立一個(gè)“緩沖池”。預(yù)先在緩沖池中放入一定數(shù)量的連接,當(dāng)需要建立數(shù)據(jù)庫(kù)連接時(shí),只需從“緩沖池”中取出一個(gè),使用完畢之后再放回去。
數(shù)據(jù)庫(kù)連接池負(fù)責(zé)分配、管理和釋放數(shù)據(jù)庫(kù)連接,它允許應(yīng)用程序重復(fù)使用一個(gè)現(xiàn)有的數(shù)據(jù)庫(kù)連接,而不是重新建立一個(gè)。
數(shù)據(jù)庫(kù)連接池在初始化時(shí)將創(chuàng)建一定數(shù)量的數(shù)據(jù)庫(kù)連接放到連接池中,這些數(shù)據(jù)庫(kù)連接的數(shù)量是由最小數(shù)據(jù)庫(kù)連接數(shù)來(lái)設(shè)定的。無(wú)論這些數(shù)據(jù)庫(kù)連接是否被使用,連接池都將一直保證至少擁有這么多的連接數(shù)量。連接池的最大數(shù)據(jù)庫(kù)連接數(shù)量限定了這個(gè)連接池能占有的最大連接數(shù),當(dāng)應(yīng)用程序向連接池請(qǐng)求的連接數(shù)超過(guò)最大連接數(shù)量時(shí),這些請(qǐng)求將被加入到等待隊(duì)列中。
數(shù)據(jù)庫(kù)連接池的工作原理
數(shù)據(jù)庫(kù)連接池技術(shù)的優(yōu)點(diǎn)
資源重用
由于數(shù)據(jù)庫(kù)連接得以重用,避免了頻繁創(chuàng)建,釋放連接引起的大量性能開(kāi)銷。在減少系統(tǒng)消耗的基礎(chǔ)上,另一方面也增加了系統(tǒng)運(yùn)行環(huán)境的平穩(wěn)性。
更快的系統(tǒng)反應(yīng)速度
數(shù)據(jù)庫(kù)連接池在初始化過(guò)程中,往往已經(jīng)創(chuàng)建了若干數(shù)據(jù)庫(kù)連接置于連接池中備用。此時(shí)連接的初始化工作均已完成。對(duì)于業(yè)務(wù)請(qǐng)求處理而言,直接利用現(xiàn)有可用連接,避免了數(shù)據(jù)庫(kù)連接初始化和釋放過(guò)程的時(shí)間開(kāi)銷,從而減少了系統(tǒng)的響應(yīng)時(shí)間。
新的資源分配手段
對(duì)于多應(yīng)用共享同一數(shù)據(jù)庫(kù)的系統(tǒng)而言,可在應(yīng)用層通過(guò)數(shù)據(jù)庫(kù)連接池的配置,實(shí)現(xiàn)某一應(yīng)用最大可用數(shù)據(jù)庫(kù)連接數(shù)的限制,避免某一應(yīng)用獨(dú)占所有的數(shù)據(jù)庫(kù)資源。
統(tǒng)一的連接管理,避免數(shù)據(jù)庫(kù)連接泄露
在較為完善的數(shù)據(jù)庫(kù)連接池實(shí)現(xiàn)中,可根據(jù)預(yù)先的占用超時(shí)設(shè)定,強(qiáng)制回收被占用連接,從而避免了常規(guī)數(shù)據(jù)庫(kù)連接操作中可能出現(xiàn)的資源泄露。
兩種開(kāi)源的數(shù)據(jù)庫(kù)連接池 :
JDBC 的數(shù)據(jù)庫(kù)連接池使用 javax.sql.DataSource 來(lái)表示,DataSource 只是一個(gè)接口,該接口通常由服務(wù)器(Weblogic, WebSphere, Tomcat)提供實(shí)現(xiàn),也有一些開(kāi)源組織
提供實(shí)現(xiàn):
DBCP 數(shù)據(jù)庫(kù)連接池
C3P0 數(shù)據(jù)庫(kù)連接池
DataSource 通常被稱為數(shù)據(jù)源,它包含連接池和連接池管理兩個(gè)部分,習(xí)慣上也經(jīng)常把 DataSource 稱為連接池。
DataSource用來(lái)取代DriverManager來(lái)獲取Connection,獲取速度快,同時(shí)可以大幅度提高數(shù)據(jù)庫(kù)訪問(wèn)速度。
DBCP 數(shù)據(jù)源?
DBCP 是 Apache 軟件基金組織下的開(kāi)源連接池實(shí)現(xiàn),該連接池依賴該組織下的另一個(gè)開(kāi)源系統(tǒng):Common-pool. 如需使用該連接池實(shí)現(xiàn),應(yīng)在系統(tǒng)中增加如下兩個(gè) jar 文件:
Commons-dbcp.jar:連接池的實(shí)現(xiàn)
Commons-pool.jar:連接池實(shí)現(xiàn)的依賴庫(kù)
Tomcat 的連接池正是采用該連接池來(lái)實(shí)現(xiàn)的。該數(shù)據(jù)庫(kù)連接池既可以與應(yīng)用服務(wù)器整合使用,也可由應(yīng)用程序獨(dú)立使用。
DBCP 數(shù)據(jù)源使用范例
數(shù)據(jù)源和數(shù)據(jù)庫(kù)連接不同,數(shù)據(jù)源無(wú)需創(chuàng)建多個(gè),它是產(chǎn)生數(shù)據(jù)庫(kù)連接的工廠,因此整個(gè)應(yīng)用只需要一個(gè)數(shù)據(jù)源即可。
當(dāng)數(shù)據(jù)庫(kù)訪問(wèn)結(jié)束后,程序還是像以前一樣關(guān)閉數(shù)據(jù)庫(kù)連接:conn.close(); 但上面的代碼并沒(méi)有關(guān)閉數(shù)據(jù)庫(kù)的物理連接,它僅僅把數(shù)據(jù)庫(kù)連接釋放,歸還給了數(shù)據(jù)庫(kù)連接池。
7-數(shù)據(jù)庫(kù)事務(wù)
事務(wù):一組邏輯操作單元,使數(shù)據(jù)從一種狀態(tài)變換到另一種狀態(tài)。
事務(wù)處理(事務(wù)操作):保證所有事務(wù)都作為一個(gè)工作單元來(lái)執(zhí)行,即使出現(xiàn)了故障,都不能改變這種執(zhí)行方式。當(dāng)在一個(gè)事務(wù)中執(zhí)行多個(gè)操作時(shí),要么所有的事務(wù)都被提交(commit),那么這些修改就永久地保存下來(lái);要么數(shù)據(jù)庫(kù)管理系統(tǒng)將放棄所作的所有修改,整個(gè)事務(wù)回滾(rollback)到最初狀態(tài)。
為確保數(shù)據(jù)庫(kù)中數(shù)據(jù)的一致性,數(shù)據(jù)的操縱應(yīng)當(dāng)是離散的成組的邏輯單元:當(dāng)它全部完成時(shí),數(shù)據(jù)的一致性可以保持,而當(dāng)這個(gè)單元中的一部分操作失敗,整個(gè)事務(wù)應(yīng)全部視為錯(cuò)誤,所有從起始點(diǎn)以后的操作應(yīng)全部回退到開(kāi)始狀態(tài)。
事務(wù)的ACID(acid)屬性 ? ?
1. 原子性(Atomicity)
原子性是指事務(wù)是一個(gè)不可分割的工作單位,事務(wù)中的操作要么都發(fā)生,要么都不發(fā)生。?
2. 一致性(Consistency)
事務(wù)必須使數(shù)據(jù)庫(kù)從一個(gè)一致性狀態(tài)變換到另外一個(gè)一致性狀態(tài)。
3. 隔離性(Isolation)
事務(wù)的隔離性是指一個(gè)事務(wù)的執(zhí)行不能被其他事務(wù)干擾,即一個(gè)事務(wù)內(nèi)部的操作及使用的數(shù)據(jù)對(duì)并發(fā)的其他事務(wù)是隔離的,并發(fā)執(zhí)行的各個(gè)事務(wù)之間不能互相干擾。
4. 持久性(Durability)
持久性是指一個(gè)事務(wù)一旦被提交,它對(duì)數(shù)據(jù)庫(kù)中數(shù)據(jù)的改變就是永久性的,接下來(lái)的其他操作和數(shù)據(jù)庫(kù)故障不應(yīng)該對(duì)其有任何影響
JDBC 事務(wù)處理
當(dāng)一個(gè)連接對(duì)象被創(chuàng)建時(shí),默認(rèn)情況下是自動(dòng)提交事務(wù):每次執(zhí)行一個(gè) SQL 語(yǔ)句時(shí),如果執(zhí)行成功,就會(huì)向數(shù)據(jù)庫(kù)自動(dòng)提交,而不能回滾。
為了讓多個(gè) SQL 語(yǔ)句作為一個(gè)事務(wù)執(zhí)行:
調(diào)用 Connection 對(duì)象的 setAutoCommit(false); 以取消自動(dòng)提交事務(wù)
在所有的 SQL 語(yǔ)句都成功執(zhí)行后,調(diào)用 commit(); 方法提交事務(wù)
在出現(xiàn)異常時(shí),調(diào)用 rollback(); 方法回滾事務(wù)
若此時(shí) Connection 沒(méi)有被關(guān)閉, 則需要恢復(fù)其自動(dòng)提交狀態(tài)
提交后的數(shù)據(jù)狀態(tài)
數(shù)據(jù)的改變已經(jīng)被保存到數(shù)據(jù)庫(kù)中。
改變前的數(shù)據(jù)已經(jīng)丟失。
所有用戶可以看到結(jié)果。
鎖被釋放, 其他用戶可以操作涉及到的數(shù)據(jù)。
8-DBUtils工具類
將常用的操作數(shù)據(jù)庫(kù)的JDBC的類和方法集合在一起,就是DBUtils.
BeanHandler:把結(jié)果集轉(zhuǎn)為一個(gè) JavaBean
BeanBeanListHandler:把結(jié)果集轉(zhuǎn)為一個(gè) Bean 的集合
MapHandler:把結(jié)果集轉(zhuǎn)為一個(gè) Map
MapMapListHandler:把結(jié)果集轉(zhuǎn)為一個(gè) Map 的 List
ScalarHandler:把結(jié)果集轉(zhuǎn)為一個(gè)類型的數(shù)據(jù)返回, 該類型通常指 String 或其它 8 種基本數(shù)據(jù)類型.
以上就是JDBC–數(shù)據(jù)庫(kù)管理系統(tǒng)的內(nèi)容,更多相關(guān)內(nèi)容請(qǐng)關(guān)注PHP中文網(wǎng)(www.php.cn)!