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