JDBC的全稱是Java DataBase Connection,也就是Java數(shù)據(jù)庫(kù)連接,我們可以?它來(lái)操作關(guān)系型數(shù)據(jù)庫(kù)。JDBC接?及相關(guān)類在java.sql 包和javax.sql包?。我們可以?它來(lái)連接數(shù)據(jù)庫(kù),執(zhí)?SQL查詢,存儲(chǔ)過(guò)程,并處理返回的結(jié)果。
JDBC接?讓Java程序和JDBC驅(qū)動(dòng)實(shí)現(xiàn)了松耦合,使得切換不同的數(shù)據(jù)庫(kù)變得更加簡(jiǎn)單。
1.com.mysql.cj.jdbc.Driver是Driver驅(qū)動(dòng)所在的位置,加載驅(qū)動(dòng)
2.Class.forName()是一個(gè)反射,但是他沒(méi)有返回一個(gè)Class對(duì)象,因?yàn)槲覀儾恍枰?br />
這是Driver的代碼:
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
它除了構(gòu)造方法,就只有一個(gè)靜態(tài)代碼塊,當(dāng)我們反射進(jìn)行的時(shí)候,這個(gè)類就開(kāi)始初始化,他的靜態(tài)代碼塊內(nèi)容就已經(jīng)被執(zhí)行了,我們真正需要的是DriverManager.registerDriver(new Driver());這一行代碼
是一個(gè)工廠類,我們通過(guò)它來(lái)創(chuàng)建數(shù)據(jù)庫(kù)連接,當(dāng)JDBC的Driver類被加載進(jìn)來(lái)時(shí),它會(huì)自己注冊(cè)到DriverManager類里面
1.注冊(cè)驅(qū)動(dòng)
2.獲取連接
3.創(chuàng)建一個(gè)Statement語(yǔ)句對(duì)象
4.執(zhí)行SQL語(yǔ)句
5.處理結(jié)果集
6.關(guān)閉資源
1.PreparedStatement 繼承于 Statement,Statement 一般用于執(zhí)行固定的沒(méi)有參數(shù)的SQL。2.PreparedStatement 一般用于執(zhí)行有?參數(shù)預(yù)編譯的SQL語(yǔ)句。可以防止SQL注入,安全性高于Statement。3.CallableStatement適用于執(zhí)行存儲(chǔ)過(guò)程。
1)Statement的execute(String query)?法?來(lái)執(zhí)?任意的SQL查詢,如果查詢的結(jié)果是?個(gè)ResultSet,這個(gè)?法就返回true。如果結(jié)果不是ResultSet,?如insert或者update查詢,它就會(huì)返回false。
2)Statement的executeQuery(String query)接??來(lái)執(zhí)?select查詢,并且返回ResultSet。即使查詢不到記錄返回的ResultSet也不會(huì)為null。我們通常使?executeQuery來(lái)執(zhí)?查詢語(yǔ)句,這樣的話如果傳進(jìn)來(lái)的是insert或者update語(yǔ)句的 話,它會(huì)拋出錯(cuò)誤信息為“executeQuery method can not be used for update”的java.util.SQLException。
3)Statement的executeUpdate(String query)?法?來(lái)執(zhí)?insert或者update/delete(DML)語(yǔ)句。
4)只有當(dāng)你不確定是什么語(yǔ)句的時(shí)候才應(yīng)該使?execute()?法,否則應(yīng)該使?executeQuery或者executeUpdate?法。
最好的辦法是利用sql語(yǔ)句進(jìn)行分頁(yè),這樣每次查詢出的結(jié)果集中就只包含某頁(yè)的數(shù)據(jù)內(nèi)容。
sql語(yǔ)句分頁(yè),不同的數(shù)據(jù)庫(kù)下的分頁(yè)方案各不一樣,假設(shè)一共有38條數(shù)據(jù),每頁(yè)有10條數(shù)據(jù),查詢第3頁(yè)的數(shù)據(jù),下面是主流的三種數(shù)據(jù)庫(kù)的分頁(yè)sql:
Oracle:
select * from
(select *,rownum as tempid from student ) t
where t.tempid between 20 and 30;
mysql:
select * from students limit 20,10;
sql server:
select top 10 * from students where id not in?
(select top 20 id from students order by id)?
order by id;
事務(wù)是作為單個(gè)邏輯?作單元執(zhí)?的?系列操作,?個(gè)邏輯?作單元必須有四個(gè)屬性,稱為原?性、?致性、隔離性和持久性(ACID) 屬性,只有這樣才能成為?個(gè)事務(wù) 。JDBC處理事務(wù)有如下操作:
conn.setAutoComit(false);設(shè)置提交?式為??提交。
conn.commit()提交事務(wù)。
conn.rollback()回滾事務(wù)。
提交與回滾只選擇?個(gè)執(zhí)?。正常情況下提交事務(wù),如果出現(xiàn)異常,則回滾。
數(shù)據(jù)庫(kù)連接是?種關(guān)鍵的有限的昂貴的資源,對(duì)數(shù)據(jù)庫(kù)連接的管理能顯著影響到整個(gè)應(yīng)?程序的伸縮性和健壯性,影響到程序 的性能指標(biāo)。數(shù)據(jù)庫(kù)連接池正是針對(duì)這個(gè)問(wèn)題提出來(lái)的。
數(shù)據(jù)庫(kù)連接池負(fù)責(zé)分配、管理和釋放數(shù)據(jù)庫(kù)連接,它允許應(yīng)?程序重復(fù)使??個(gè)現(xiàn)有的數(shù)據(jù)庫(kù)連接,?不是重新建??個(gè);釋放空閑時(shí)間超過(guò)最?空閑時(shí)間的數(shù)據(jù)庫(kù)連接來(lái)避免因?yàn)闆](méi)有釋放數(shù)據(jù)庫(kù)連接?引起的數(shù)據(jù)庫(kù)連接遺漏。這項(xiàng)技術(shù)能明顯提?對(duì)數(shù)據(jù)庫(kù)操作的性能。
數(shù)據(jù)庫(kù)連接池在初始化時(shí)將創(chuàng)建?定數(shù)量的數(shù)據(jù)庫(kù)連接放到連接池中,這些數(shù)據(jù)庫(kù)連接的數(shù)量是由最?數(shù)據(jù)庫(kù)連接數(shù)來(lái)設(shè)定的。?論這些數(shù)據(jù)庫(kù)連接是否被使?,連接池都將?直保證?少擁有這么多的連接數(shù)量。連接池的最?數(shù)據(jù)庫(kù)連接數(shù)量限定了這個(gè)連接池能占有的最?連接數(shù),當(dāng)應(yīng)?程序向連接池請(qǐng)求的連接數(shù)超過(guò)最?連接數(shù)量時(shí),這些請(qǐng)求將被加?到等待隊(duì)列中。
橋接模式,首先DriverManager獲得Connection是通過(guò)反射和類加載機(jī)制從數(shù)據(jù)庫(kù)驅(qū)動(dòng)包的driver中拿到連接,所以這里真正參與橋接模式的是driver,而DriverManager和橋接模式?jīng)]有關(guān)系,DriverManager只是對(duì)driver的一個(gè)管理器。而我們作為使用者只去關(guān)心Connection,不會(huì)去關(guān)心driver,因?yàn)槲覀兊牟僮鞫际峭ㄟ^(guò)操作Connection來(lái)實(shí)現(xiàn)的。這樣分析下來(lái)這個(gè)橋接就清晰了邏輯——java.sql.Driver作為抽象橋類,而驅(qū)動(dòng)包如com.mysql.jdbc.Driver具體的實(shí)現(xiàn)橋接類,而Connection是被橋接的對(duì)象。
默認(rèn)情況下,我們創(chuàng)建的數(shù)據(jù)庫(kù)連接,是工作在自動(dòng)提交的模式下的。這意味著只要我們執(zhí)行完一條查詢語(yǔ)句,就會(huì)自動(dòng)進(jìn)行提交。因此我們的每條查詢,實(shí)際上都是一個(gè)事務(wù),如果我們執(zhí)行的是DML或者DDL,每條語(yǔ)句完成的時(shí)候,數(shù)據(jù)庫(kù)就已經(jīng)完成修改了。有的時(shí)候我們希望由一組SQL查詢組成一個(gè)事務(wù),如果它們都執(zhí)行OK我們?cè)龠M(jìn)行提交,如果中途出現(xiàn)異常了,我們可以進(jìn)行回滾。
JDBC接口提供了一個(gè)setAutoCommit(boolean flag)方法,我們可以用它來(lái)關(guān)閉連接自動(dòng)提交的特性。我們應(yīng)該在需要手動(dòng)提交時(shí)才關(guān)閉這個(gè)特性,不然的話事務(wù)不會(huì)自動(dòng)提交,每次都得手動(dòng)提交。數(shù)據(jù)庫(kù) 通過(guò)表鎖來(lái)管理事務(wù),這個(gè)操作非常消耗資源。因此我們應(yīng)當(dāng)完成操作后盡快的提交事務(wù)。在這里有更多關(guān)于事務(wù)的示例程序。
CLOB意思是Character Large OBjects,字符大對(duì)象,它是由單字節(jié)字符組成的字符串?dāng)?shù)據(jù),有自己專門(mén)的代碼頁(yè)。這種數(shù)據(jù)類型適用于存儲(chǔ)超長(zhǎng)的文本信息,那些可能會(huì)超出標(biāo)準(zhǔn)的VARCHAR數(shù)據(jù)類型長(zhǎng)度限制(上限是32KB)的文本。
BLOB是Binary Larget OBject,它是二進(jìn)制大對(duì)象,由二進(jìn)制數(shù)據(jù)組成,沒(méi)有專門(mén)的代碼頁(yè)。它能用于存儲(chǔ)超過(guò)VARBINARY限制(32KB)的二進(jìn)制數(shù)據(jù)。這種數(shù)據(jù)類型適合存儲(chǔ)圖片,聲音,圖形,或者其它業(yè)務(wù)程序特定的數(shù)據(jù)。
每個(gè)類都有一個(gè) Class 對(duì)象,包含了與類有關(guān)的信息。當(dāng)編譯一個(gè)新類時(shí),會(huì)產(chǎn)生一個(gè)同名的 .class 文件,該文件內(nèi)容保存著 Class 對(duì)象。類加載相當(dāng)于 Class 對(duì)象的加載,類在第一次使用時(shí)才動(dòng)態(tài)加載到 JVM 中。也可以使用 Class.forName,這種方式來(lái)控制類的加載,該方法會(huì)返回一個(gè) Class 對(duì)象。
反射可以提供運(yùn)行時(shí)的類信息,并且這個(gè)類可以在運(yùn)行時(shí)才加載進(jìn)來(lái),甚至在編譯時(shí)期該類的 .class 不存在也可以加載進(jìn)來(lái)。Class 和 java.lang.reflect 一起對(duì)反射提供了支持,java.lang.reflect 類庫(kù)主要包含了以下三個(gè)類:
(1)Field :可以使用 get() 和 set() 方法讀取和修改 Field 對(duì)象關(guān)聯(lián)的字段;
(2)Method :可以使用 invoke() 方法調(diào)用與 Method 對(duì)象關(guān)聯(lián)的方法;
(3)Constructor :可以用 Constructor 創(chuàng)建新的對(duì)象。
應(yīng)用舉例:工廠模式,使用反射機(jī)制,根據(jù)全限定類名獲得某個(gè)類的 Class 實(shí)例。
反射是用來(lái)描述類的信息的。對(duì)于任意一個(gè)類,都能夠知道這個(gè)類的所有屬性和方法;對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意一個(gè)方法和屬性;這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱為 Java 語(yǔ)言的反射機(jī)制。
class:用來(lái)描述類本身
Packge:用來(lái)描述類所屬的包
Field:用來(lái)描述類中的屬性
Method:用來(lái)描述類中的方法
Constructor:用來(lái)描述類中的構(gòu)造方法
Annotation:用來(lái)描述類中的注解
1)Class clazz=class.forName("包名.類名")
2)Class clazz=類名.class;
3)Class clazz=對(duì)象.getClass();
(1)獲取類的權(quán)限修飾符--------->int result=getModifiers();
(2)獲取名字------------>string name=clazz.getName();
(3)獲取包名------------>Packge p=clazz.getPackge();
(4)尋找clazz中無(wú)參數(shù)構(gòu)造方法:Clazz.getConstructor([String.class]);
執(zhí)行構(gòu)造方法創(chuàng)建對(duì)象:Con.newInstance([參數(shù)]);
(5)Field c=cls.getFields():獲得某個(gè)類的所有的公共(public)的字段,包括父類中的字段。
Field c=cls.getDeclaredFields():獲得某個(gè)類的所有聲明的字段,即包括public、private和 proteced,但是不包括父類的聲明字段。
(1)反射得經(jīng)典用法就是在xml或者properties配置文件中,然后在java類里面區(qū)解析這些內(nèi)容,得到一個(gè)字符串,然后通過(guò)反射機(jī)制,通過(guò)這些字符串獲得某個(gè)類得class實(shí)例,這樣的話就可以動(dòng)態(tài)的配置一些東西,而不需要每次都重新去new,要改的話也是直接改配置文件,代碼維護(hù)起來(lái)方便很多。
(2)當(dāng)你在做一個(gè)軟件開(kāi)發(fā)的插件的時(shí)候,你連插件的類型名稱都不知道,你怎么實(shí)例化這個(gè)對(duì)象呢?因?yàn)槌绦蚴侵С植寮模ǖ谌降模陂_(kāi)發(fā)的時(shí)候并不知道 。所以無(wú)法在代碼中 New出來(lái) ,但反射可以,通過(guò)反射,動(dòng)態(tài)加載程序集,然后讀出類,檢查標(biāo)記之后再實(shí)例化對(duì)象,就可以獲得正確的類實(shí)例。
(3)在編碼階段不知道那個(gè)類名,要在運(yùn)行期從配置文件讀取類名, 這時(shí)候就沒(méi)有辦法硬編碼new ClassName(),而必須用到反射才能創(chuàng)建這個(gè)對(duì)象.反射的目的就是為了擴(kuò)展未知的應(yīng)用。比如你寫(xiě)了一個(gè)程序,這個(gè)程序定義了一些接口,只要實(shí)現(xiàn)了這些接口的dll都可以作為插件來(lái)插入到這個(gè)程序中。那么怎么實(shí)現(xiàn)呢?就可以通過(guò)反射來(lái)實(shí)現(xiàn)。就是把dll加載進(jìn)內(nèi)存,然后通過(guò)反射的方式來(lái)調(diào)用dll中的方法。很多工廠模式就是使用的反射。
getSimpleName:只獲取類名
getName:類的全限定名,jvm中Class的表示,可以用于動(dòng)態(tài)加載Class對(duì)象,例如Class.forName。
getCanonicalName:返回更容易理解的表示,主要用于輸出(toString)或log打印,大多數(shù)情況下和getName一樣,但是在內(nèi)部類、數(shù)組等類型的表示形式就不同了。