Java學習筆記(5)JDBC
JDBC簡介
JDBC簡介:
JDBC代表Java資料庫連線(**J**ava **D**ata**b**ase **C**onnectivity),它是用於Java程式語言和資料庫之間的資料庫無關連線的標準Java API,換句話說:JDBC是用於在Java語言程式設計中與資料庫連線的API。
JDBC庫包括通常與資料庫使用相關,如下面提到的每個任務的API -
- 連線到資料庫
- 建立SQL或MySQL語句
- 在資料庫中執行SQL或MySQL查詢
- 檢視和修改結果記錄
從根本上說,JDBC是一個規範,它提供了一整套介面,允許以一種可移植的訪問底層資料庫API。 Java可以用它來編寫不同型別的可執行檔案,如 -
- Java應用程式
- Java Applet
- Java Servlets
- Java ServerPages(JSP)
- 企業級JavaBeans(EJB)
所有這些不同的可執行檔案都能夠使用JDBC驅動程式來訪問資料庫,並用於儲存資料到資料庫中。
JDBC提供與ODBC相同的功能,允許Java程式包含與資料庫無關的程式碼(同樣的程式碼,只需要指定使用的資料庫型別,不需要重修改資料庫查詢或操作程式碼)。
JDBC架構:
JDBC API支援用於資料庫訪問的兩層和三層處理模型,但通常,JDBC體系結構由兩層組成:
- JDBC API:提供應用程式到JDBC管理器連線。
- JDBC驅動程式API:支援JDBC管理器到驅動程式連線。
JDBC API使用驅動程式管理器並指定資料庫的驅動程式來提供與異構資料庫的透明連線。
JDBC驅動程式管理器確保使用正確的驅動程式來訪問每個資料來源。 驅動程式管理器能夠支援連線到多個異構資料庫的多個併發驅動程式。
以下是架構圖,它顯示了驅動程式管理器相對於JDBC驅動程式和Java應用程式的位置 -
常見的JDBC元件:
JDBC API提供以下介面和類 :
DriverManager
:此類管理資料庫驅動程式列表。 使用通訊子協議將來自java應用程式的連線請求與適當的資料庫驅動程式進行匹配。在JDBC下識別某個子協議的第一個驅動程式將用於建立資料庫連線。Driver
:此介面處理與資料庫伺服器的通訊。我們很少會直接與Driver
物件進行互動。 但會使用DriverManager
物件來管理這種型別的物件。 它還提取與使用Driver
物件相關的資訊。Connection
:此介面具有用於聯絡資料庫的所有方法。 連線(Connection
)物件表示通訊上下文,即,與資料庫的所有通訊僅通過連線物件。Statement
:使用從此介面建立的物件將SQL語句提交到資料庫。 除了執行儲存過程之外,一些派生介面還接受引數。ResultSet
:在使用Statement
物件執行SQL查詢後,這些物件儲存從資料庫檢索的資料。 它作為一個迭代器並可移動ResultSet
物件查詢的資料。SQLException
:此類處理資料庫應用程式中發生的任何錯誤。
它裡面包含了上面的這些類。
JDBC驅動程式型別:
JDBC驅動程式是什麼?
JDBC驅動程式在JDBC API中實現定義的介面,用於與資料庫伺服器進行互動。
例如,使用JDBC驅動程式,可以通過傳送SQL或資料庫命令,然後使用Java接收結果來開啟資料庫連線並與資料庫進行互動。
JDK附帶的Java.sql
包包含各種類,其類的行為被定義,實現在第三方驅動程式中完成。 第三方供應商在其資料庫驅動程式中實現java.sql.Driver
介面。
JDBC驅動程式型別:
JDBC驅動程式實現因Java執行的各種作業系統和硬體平臺而異。 Sun將實現型別分為四種類型,分別為1
,2
,3
和4
型別,如下所述:
型別1:JDBC-ODBC橋驅動程式
在型別1驅動程式中,JDBC橋接器用於訪問安裝在每臺客戶機上的ODBC驅動程式。 使用ODBC需要在系統上配置表示目標資料庫的資料來源名稱(DSN)。
當Java第一次出現時,這是一個驅動程式,因為大多數資料庫僅支援ODBC訪問,但現在這種型別的驅動程式僅推薦用於實驗性使用或沒有其他替代方案時使用。
型別2:JDBC本地API
在型別2驅動程式中,JDBC API呼叫將轉換為本地C/C++ API呼叫,這是資料庫唯一的。 這些驅動程式通常由資料庫供應商提供,並以與JDBC-ODBC橋接相同的方式使用。 必須在每個客戶機上安裝供應商特定的驅動程式。
如果要更改資料庫,則必須更改原生API,因為它特定於資料庫,並且現在大部分已經過時,但是使用型別2驅動程式實現了一些擴充套件功能的開發,它消除了ODBC的開銷。
型別3:JDBC-Net純Java
在型別3驅動程式中,使用三層方法訪問資料庫。 JDBC客戶端使用標準網路套接字與中介軟體應用程式伺服器進行通訊。 套接字資訊隨後由中介軟體應用伺服器轉換成DBMS所需的呼叫格式,並轉發到資料庫伺服器。
這種驅動程式是非常靈活的,因為它不需要在客戶端上安裝程式碼,一個驅動程式實際上可以提供多個數據庫的訪問。
可以將應用程式伺服器視為JDBC“代理”,它會呼叫客戶端應用程式。 因此,我們需要了解應用程式伺服器的配置,才能有效地使用此驅動程式型別。
應用程式伺服器可能會使用型別1,2或4驅動程式與資料庫通訊,瞭解細微差別對理解JDBC是有幫助的。
型別4:100%純Java
在型別4驅動程式中,基於純Java的驅動程式通過套接字連線與供應商的資料庫直接通訊。 這是資料庫可用的最高效能驅動程式,通常由供應商自己提供。
這種驅動是非常靈活的,不需要在客戶端或伺服器上安裝特殊的軟體。 此外,這些驅動程式可以動態下載。
MySQL
Connector/J
驅動程式是型別4驅動程式。 由於其網路協議的專有性質,資料庫供應商通常提供型別4驅動程式。
怎麼選擇驅動程式:
- 如果在訪問一種型別的資料庫,例如Oracle,Sybase或IBM DB2,則首選驅動程式型別為型別4。
- 如果Java應用程式同時訪問多種型別的資料庫,則型別3是首選驅動程式。
- 型別2驅動程式在資料庫不可用的型別3或型別4驅動程式的情況下使用。
- 型別1驅動程式不被視為部署級驅動程式,通常僅用於開發和測試目的。
JDBC程式設計
JDBC SQL語法:
建立JDBC應用程式的一般步驟:
構建JDBC應用程式涉及以下六個步驟 -
- 匯入包:需要包含包含資料庫程式設計所需的JDBC類的包。 大多數情況下,使用
import java.sql.*
就足夠了。 - 註冊JDBC驅動程式:需要初始化驅動程式,以便可以開啟與資料庫的通訊通道。
- 開啟一個連線:需要使用
DriverManager.getConnection()
方法建立一個Connection
物件,它表示與資料庫的物理連線。 - 執行查詢:需要使用型別為
Statement
的物件來構建和提交SQL語句到資料庫。 - 從結果集中提取資料:需要使用相應的
ResultSet.getXXX()
方法從結果集中檢索資料。 - 清理環境:需要明確地關閉所有資料庫資源,而不依賴於JVM的垃圾收集。
JDBC資料庫連線:
建立JDBC連線所涉及的程式設計相當簡單。 以下是基本的四個步驟 -
- 匯入JDBC包:使用Java語言的
import
語句在Java程式碼開頭位置匯入所需的類。 - 註冊JDBC驅動程式:使JVM將所需的驅動程式實現載入到記憶體中,從而可以滿足JDBC請求。
- 資料庫URL配置:建立一個正確格式化的地址,指向要連線到的資料庫(如:MySQL,Oracle和MSSQL等等)。
- 建立連線物件:最後,呼叫
DriverManager
物件的getConnection()
方法來建立實際的資料庫連線。
註冊驅動程式的方法:
方法1:Class.forName()
註冊驅動程式最常見的方法是使用Java的Class.forName()
方法,將驅動程式的類檔案動態載入到記憶體中,並將其自動註冊。這個方法是推薦使用的方法,因為它使驅動程式註冊可配置和便攜。
以下示例使用Class.forName()
註冊Oracle驅動程式 -
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
}
catch(ClassNotFoundException ex) {
System.out.println("Error: unable to load driver class!");
System.exit(1);
}
使用JDBC驅動程式連線MySQL資料庫的示例程式碼片段 -
Class.forName("com.mysql.jdbc.Driver");
Connection conn = null;
conn = DriverManager.getConnection("jdbc:mysql://hostname:port/db_name","db_username", "db_password");
conn.close();
使用getInstance()
方法來解決不合規的JVM,但是必須編寫兩個額外的異常,如下所示:
try {
Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
}
catch(ClassNotFoundException ex) {
System.out.println("Error: unable to load driver class!");
System.exit(1);
catch(IllegalAccessException ex) {
System.out.println("Error: access problem while loading!");
System.exit(2);
catch(InstantiationException ex) {
System.out.println("Error: unable to instantiate driver!");
System.exit(3);
}
方法2 - DriverManager.registerDriver()
第二種方法是使用靜態DriverManager.registerDriver()
方法來註冊驅動程式。
如果使用的是非JDK相容的JVM(如Microsoft提供的),則應使用registerDriver()
方法。
以下示例使用registerDriver()
註冊Oracle驅動程式 -
try {
Driver myDriver = new oracle.jdbc.driver.OracleDriver();
DriverManager.registerDriver( myDriver );
}
catch(ClassNotFoundException ex) {
System.out.println("Error: unable to load driver class!");
System.exit(1);
}
資料庫URL配置:
載入驅動程式後,可以使用DriverManager.getConnection()
方法建立連線。 為了方便參考,這裡列出三個過載的DriverManager.getConnection()
方法 -
getConnection(String url)
getConnection(String url, Properties prop)
getConnection(String url, String user, String password)
這裡每個格式都需要一個數據庫URL。 資料庫URL是指向資料庫的地址。
制定資料庫URL是建立連線相關聯的大多數錯誤問題發生的地方。
下表列出了常用的JDBC驅動程式名稱和資料庫URL。
RDBMS | JDBC驅動程式名稱 | URL格式 |
---|---|---|
MySQL | com.mysql.jdbc.Driver |
jdbc:mysql://hostname/databaseName |
ORACLE | oracle.jdbc.driver.OracleDriver |
jdbc:oracle:thin:@hostname:portNumber:databaseName |
PostgreSQL | org.postgresql.Driver |
jdbc:postgresql://hostname:port/dbname |
DB2 | com.ibm.db2.jdbc.net.DB2Driver |
jdbc:db2:hostname:port Number/databaseName |
Sybase | com.sybase.jdbc.SybDriver |
jdbc:sybase:Tds:hostname: portNumber/databaseName |
URL格式的所有突出部分都是靜態的,只需要根據資料庫設定更改對應的部分。
JDBC Statements類:
當獲得了與資料庫的連線後,就可以與資料庫進行互動了。 JDBC Statement
,CallableStatement
和PreparedStatement
介面定義了可用於傳送SQL或PL/SQL命令,並從資料庫接收資料的方法和屬性。
它們還定義了有助於在Java和SQL資料型別的資料型別差異轉換的方法。
下表提供了每個介面定義,以及使用這些介面的目的的總結。
介面 | 推薦使用 |
---|---|
Statement |
用於對資料庫進行通用訪問,在執行時使用靜態SQL語句時很有用。 Statement 介面不能接受引數。 |
PreparedStatement |
當計劃要多次使用SQL語句時使用。PreparedStatement 介面在執行時接受輸入引數。 |
CallableStatement |
當想要訪問資料庫儲存過程時使用。CallableStatement 介面也可以接受執行時輸入引數。 |
Statement物件
1. 建立Statement物件
在使用Statement
物件執行SQL語句之前,需要使用Connection
物件的createStatement()
方法建立一個Statement
物件,如以下示例所示:
Statement stmt = null;
try {
stmt = conn.createStatement( );
. . .
}
catch (SQLException e) {
. . .
}
finally {
. . .
}
在建立Statement
物件後,可以使用它來執行一個SQL語句,它有三個執行方法可以執行。它們分別是 -
boolean execute (String SQL)
: 如果可以檢索到ResultSet
物件,則返回一個布林值true
; 否則返回false
。使用此方法執行SQLDDL
語句或需要使用真正的動態SQL,可使用於執行建立資料庫,建立表的SQL語句等等。int executeUpdate (String SQL):
返回受SQL語句執行影響的行數。使用此方法執行預期會影響多行的SQL語句,例如:INSERT
,UPDATE
或DELETE
語句。ResultSet executeQuery(String SQL):
返回一個ResultSet
物件。 當您希望獲得結果集時,請使用此方法,就像使用SELECT
語句一樣。
2.關閉Statement物件
就像關閉一個Connection
物件一樣,以儲存資料庫資源一樣,由於同樣的原因,還應該關閉Statement
物件。
一個簡單的呼叫close()
方法將執行該作業(工作)。 如果先關閉Connection
物件,它也會關閉Statement
物件。 但是,應該始終顯式關閉Statement
物件,以確保正確的清理順序。
Statement stmt = null;
try {
stmt = conn.createStatement( );
. . .
}
catch (SQLException e) {
. . .
}
finally {
stmt.close();
}
PreparedStatement物件
PreparedStatement
介面擴充套件了Statement
介面,它添加了比Statement
物件更好一些優點的功能。
此語句可以動態地提供/接受引數。
2.1 建立PreparedStatement物件
PreparedStatement pstmt = null;
try {
String SQL = "Update Employees SET age = ? WHERE id = ?";
pstmt = conn.prepareStatement(SQL);
. . .
}
catch (SQLException e) {
. . .
}
finally {
. . .
}
JDBC中的所有引數都由 ?
符號作為佔位符,這被稱為引數標記。 在執行SQL語句之前,必須為每個引數(佔位符)提供值。
setXXX()
方法將值繫結到引數,其中XXX
表示要繫結到輸入引數的值的Java資料型別。 如果忘記提供繫結值,則將會丟擲一個SQLException
。
每個引數標記是它其順序位置引用。第一個標記表示位置1
,下一個位置2
等等。 該方法與Java陣列索引不同(它不從0
開始)。
所有Statement
物件與資料庫互動的方法(a)execute()
,(b)executeQuery()
和(c)executeUpdate()
也可以用於PreparedStatement
物件。 但是,這些方法被修改為可以使用輸入引數的SQL語句。
2.關閉PreparedStatement物件
就像關閉Statement
物件一樣,由於同樣的原因(節省資料庫系統資源),也應該關閉PreparedStatement
物件。
簡單的呼叫close()
方法將執行關閉。 如果先關閉Connection
物件,它也會關閉PreparedStatement
物件。 但是,應該始終顯式關閉PreparedStatement
物件,以確保以正確順序清理資源。
PreparedStatement pstmt = null;
try {
String SQL = "Update Employees SET age = ? WHERE id = ?";
pstmt = conn.prepareStatement(SQL);
. . .
}
catch (SQLException e) {
. . .
}
finally {
pstmt.close();
}
CallableStatement物件
類似Connection
物件建立Statement
和PreparedStatement
物件一樣,它還可以使用同樣的方式建立CallableStatement
物件,該物件將用於執行對資料庫儲存過程的呼叫。
3.1. 建立CallableStatement物件
假設需要執行以下Oracle儲存過程 -
CREATE OR REPLACE PROCEDURE getEmpName
(EMP_ID IN NUMBER, EMP_FIRST OUT VARCHAR) AS
BEGIN
SELECT first INTO EMP_FIRST
FROM Employees
WHERE ID = EMP_ID;
END;
注意:上面的儲存過程是針對Oracle編寫的,但是如果您使用MySQL資料庫,可使用以下方式來編寫MySQL相同的儲存過程,如下在EMP資料庫中建立它 -
DELIMITER $$
DROP PROCEDURE IF EXISTS `EMP`.`getEmpName` $$
CREATE PROCEDURE `EMP`.`getEmpName`
(IN EMP_ID INT, OUT EMP_FIRST VARCHAR(255))
BEGIN
SELECT first INTO EMP_FIRST
FROM Employees
WHERE ID = EMP_ID;
END $$
DELIMITER ;
存在三種類型的引數:IN
,OUT
和INOUT
。 PreparedStatement
物件只使用IN
引數。CallableStatement
物件可以使用上面三個引數型別。
以下是上面三種類型引數的定義 -
引數 | 描述 |
---|---|
IN | 建立SQL語句時其引數值是未知的。 使用setXXX() 方法將值繫結到IN 引數。 |
OUT | 由SQL語句返回的引數值。可以使用getXXX() 方法從OUT引數中檢索值。 |
INOUT | 提供輸入和輸出值的引數。使用setXXX() 方法繫結變數並使用getXXX() 方法檢索值。 |
以下程式碼片段顯示瞭如何使用Connection.prepareCall()
方法根據上述儲存過程來例項化一個CallableStatement
物件 -
CallableStatement cstmt = null;
try {
String strSQL = "{call getEmpName (?, ?)}";
cstmt = conn.prepareCall (SQL);
. . .
}
catch (SQLException e) {
. . .
}
finally {
. . .
}
String變數strSQL
表示儲存過程,帶有兩個引數佔位符。
使用CallableStatement
物件就像使用PreparedStatement
物件一樣。 在執行語句之前,必須將值繫結到所有引數,否則將丟擲一個SQLException
異常。
如果有IN
引數,只需遵循適用於PreparedStatement
物件的相同規則和技術; 使用與繫結的Java資料型別相對應的setXXX()
方法。
使用OUT
和INOUT
引數時,必須使用一個額外的CallableStatement
物件方法registerOutParameter()
。 registerOutParameter()
方法將JDBC資料型別繫結到儲存過程並返回預期資料型別。
當呼叫儲存過程,可以使用適當的getXXX()
方法從OUT
引數中檢索該值。 此方法將檢索到的SQL型別的值轉換為對應的Java資料型別。
關閉CallableStatement物件
就像關閉其他Statement
物件一樣,由於同樣的原因(節省資料庫系統資源),還應該關閉CallableStatement
物件。
簡單的呼叫close()
方法將執行關閉CallableStatemen
t物件。 如果先關閉Connection
物件,它也會關閉CallableStatement
物件。 但是,應該始終顯式關閉CallableStatement
物件,以確保按正確順序的清理資源。
CallableStatement cstmt = null;
try {
String SQL = "{call getEmpName (?, ?)}";
cstmt = conn.prepareCall (SQL);
. . .
}
catch (SQLException e) {
. . .
}
finally {
cstmt.close();
}
JDBC結果集:
SQL語句執行後從資料庫查詢讀取資料,返回的資料放在結果集中。 SELECT
語句用於從資料庫中選擇行並在結果集中檢視它們的標準方法。 java.sql.ResultSet
介面表示資料庫查詢的結果集。
ResultSet
物件維護指向結果集中當前行的遊標。 術語“結果集”是指包含在ResultSet
物件中的行和列資料。
ResultSet
介面的方法可以分為三類:
- 瀏覽方法:用於移動游標。
- 獲取方法:用於檢視游標指向的當前行的列中的資料。
- 更新方法:用於更新當前行的列中的資料。 然後在基礎資料庫中更新資料。
游標可以基於ResultSet
的屬性移動。當建立生成ResultSet
的相應Statement
時,將指定這些屬性。
JDBC提供以下連線方法來建立具有所需ResultSet
的語句 -
createStatement(int RSType, int RSConcurrency);
prepareStatement(String SQL, int RSType, int RSConcurrency);
prepareCall(String sql, int RSType, int RSConcurrency);
第一個引數表示ResultSet
物件的型別,第二個引數是兩個ResultSet
常量之一,用於指定結果集是隻讀還是可更新。
瀏覽結果集
ResultSet
介面中有幾種涉及移動游標的方法,包括 -
編號 | 方法 | 描述 |
---|---|---|
1 | public void beforeFirst() throws SQLException |
將游標移動到第一行之前 |
2 | public void afterLast() throws SQLException |
將游標移動到最後一行之後。 |
3 | public boolean first() throws SQLException |
將游標移動到第一行。 |
4 | public void last() throws SQLException |
將游標移動到最後一行。 |
5 | public boolean absolute(int row) throws SQLException |
將游標移動到指定的行。 |
6 | public boolean relative(int row) throws SQLException |
從當前指向的位置,將游標向前或向後移動給定行數。 |
7 | public boolean previous() throws SQLException |
將游標移動到上一行。 如果上一行關閉結果集,此方法返回false 。 |
8 | public boolean next() throws SQLException |
將游標移動到下一行。 如果結果集中沒有更多行,則此方法返回false 。 |
9 | public int getRow() throws SQLException |
返回游標指向的行號。 |
10 | public void moveToInsertRow() throws SQLException |
將游標移動到結果集中的特殊行,該行可用於將新行插入資料庫。當前游標位置被記住。 |
11 | public void moveToCurrentRow() throws SQLException |
如果游標當前位於插入行,則將游標移回當前行; 否則,此方法什麼也不做 |
JDBC事務:
如果JDBC連線處於自動提交模式,預設情況下,則每個SQL語句在完成後都會提交到資料庫。
對於簡單的應用程式可能沒有問題,但是有三個原因需要考慮是否關閉自動提交併管理自己的事務 -
- 提高效能
- 保持業務流程的完整性
- 使用分散式事務
事務能夠控制何時更改提交併應用於資料庫。 它將單個SQL語句或一組SQL語句視為一個邏輯單元,如果任何語句失敗,整個事務將失敗。
要啟用手動事務支援,而不是使用JDBC驅動程式預設使用的自動提交模式,請呼叫Connection
物件的setAutoCommit()
方法。 如果將布林的false
傳遞給setAutoCommit()
,則關閉自動提交。 也可以傳遞一個布林值true
來重新開啟它。
例如,如果有一個名為conn
的Connection
物件,請將以下程式碼關閉自動提交 -
conn.setAutoCommit(false);
提交和回滾
完成更改後,若要提交更改,那麼可在連線物件上呼叫commit()
方法,如下所示:
conn.commit( );
否則,要使用連線名為conn
的資料庫回滾更新,請使用以下程式碼 -
conn.rollback( );
使用儲存點
新的JDBC 3.0新添加了Savepoint
介面提供了額外的事務控制能力。大多數現代DBMS支援其環境中的儲存點,如Oracle的PL/SQL。
設定儲存點(Savepoint
)時,可以在事務中定義邏輯回滾點。 如果通過儲存點(Savepoint
)發生錯誤時,則可以使用回滾方法來撤消所有更改或僅儲存儲存點之後所做的更改。
Connection
物件有兩種新的方法可用來管理儲存點 -
- setSavepoint(String savepointName): - 定義新的儲存點,它還返回一個
Savepoint
物件。 - releaseSavepoint(Savepoint savepointName): - 刪除儲存點。要注意,它需要一個
Savepoint
物件作為引數。 該物件通常是由setSavepoint()
方法生成的儲存點。
有一個rollback (String savepointName)方法,它將使用事務回滾到指定的儲存點。
JDBC異常:
異常處理允許我們以受控的方式處理異常情況,而不是直接退出程式,例如程式定義的錯誤。
發生異常時可以丟擲異常。術語“異常”表示當前的程式執行停止,並且被重定向到最近的適用的catch
子句。如果沒有適用的catch
子句存在,則程式的執行結束。
JDBC異常處理與Java異常處理非常相似,但對於JDBC,要處理的最常見異常是java.sql.SQLException
。
SQLException方法
驅動程式和資料庫中都會發生SQLException
。 發生這種異常時,SQLException
型別的物件將被傳遞給catch
子句。
傳遞的SQLException
物件具有以下可用於檢索有關異常資訊的方法 -
方法 | 描述 |
---|---|
getErrorCode( ) |
獲取與異常關聯的錯誤程式碼。 |
getMessage( ) |
獲取驅動程式處理的錯誤的JDBC驅動程式的錯誤訊息,或獲取資料庫錯誤的Oracle錯誤程式碼和訊息。 |
getSQLState( ) |
獲取XOPEN SQLstate字串。 對於JDBC驅動程式錯誤,不會從此方法返回有用的資訊。 對於資料庫錯誤,返回五位數的XOPEN SQLstate程式碼。 此方法可以返回。 |
getNextException( ) |
獲取異常鏈中的下一個Exception 物件。 |
printStackTrace( ) |
列印當前異常或可丟擲的異常,並將其追溯到標準錯誤流。 |
printStackTrace(PrintStream s) |
將此throwable 及其回溯列印到指定的列印流。 |
printStackTrace(PrintWriter w) |
列印這個throwable ,它是回溯到指定的列印器(PrintWriter )。 |
JDBC批處理:
批量處理允許將相關的SQL語句分組到批處理中,並通過對資料庫的一次呼叫來提交它們,一次執行完成與資料庫之間的互動。
一次向資料庫傳送多個SQL語句時,可以減少通訊開銷,從而提高效能。
- 不需要JDBC驅動程式來支援此功能。應該使用
DatabaseMetaData.supportsBatchUpdates()
方法來確定目標資料庫是否支援批量更新處理。如果JDBC驅動程式支援此功能,該方法將返回true
。 Statement
,PreparedStatement
和CallableStatement
的addBatch()
方法用於將單個語句新增到批處理。executeBatch()
用於執行組成批量的所有語句。executeBatch()
返回一個整數陣列,陣列的每個元素表示相應更新語句的更新計數。- 就像將批處理語句新增到處理中一樣,可以使用
clearBatch()
方法刪除它們。此方法將刪除所有使用addBatch()
方法新增的語句。 但是,無法指定選擇某個要刪除的語句。
使用Statement物件進行批處理
以下是使用Statement
物件的批處理的典型步驟序列 -
- 使用
createStatement()
方法建立Statement
物件。 - 使用
setAutoCommit()
將自動提交設定為false
。 - 使用
addBatch()
方法在建立的Statement
物件上新增SQL語句到批處理中。 - 在建立的
Statement
物件上使用executeBatch()
方法執行所有SQL語句。 - 最後,使用
commit()
方法提交所有更改。
使用PrepareStatement物件進行批處理
以下是使用PrepareStatement
物件進行批處理的典型步驟順序 -
- 使用佔位符建立SQL語句。
- 使用
prepareStatement()
方法建立PrepareStatement
物件。 - 使用
setAutoCommit()
將自動提交設定為false
。 - 使用
addBatch()
方法在建立的Statement
物件上新增SQL語句到批處理中。 - 在建立的
Statement
物件上使用executeBatch()
方法執行所有SQL語句。 - 最後,使用
commit()
方法提交所有更改。
JDBC程式設計示例
查詢資料:
在實驗前,事先建立好了兩張表,tbl_user,和tbl_address。通過JDBC變數是查詢下面兩張表的資料。
mysql> show tables;
+------------------+
| Tables_in_jsp_db |
+------------------+
| tbl_address |
| tbl_user |
+------------------+
2 rows in set (0.00 sec)
mysql> select * from tbl_user;
+----+-----------+----------+----------------------+
| id | name | password | email |
+----+-----------+----------+----------------------+
| 1 | xiaoming | 123456 | [email protected] |
| 2 | xiaozhang | 123456 | [email protected] |
+----+-----------+----------+----------------------+
2 rows in set (0.00 sec)
mysql> select * from tbl_address;
+----+----------+---------+---------+
| id | city | country | user_id |
+----+----------+---------+---------+
| 1 | beijing | china | 1 |
| 2 | tianjing | china | 2 |
+----+----------+---------+---------+
2 rows in set (0.00 sec)
配置dbconfig.properties:
driver=com.mysql.jdbc.Driver
dburl=jdbc:mysql://localhost:3306/jsp_db?useSSL=false
user=root
password=123456
連線實體:
package JDBC.util;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;
public class ConnectionFactory {
private static String driver;
private static String dburl;
private static String user;
private static String password;
private static final ConnectionFactory factory = new ConnectionFactory();
private Connection conn;
static {
Properties prop = new Properties();
try {
InputStream in = ConnectionFactory.class.getClassLoader().
getResourceAsStream("dbconfig.properties");
prop.load(in);
} catch (Exception e) {
System.out.println("========配置檔案讀取錯誤========");
}
driver = prop.getProperty("driver");
dburl = prop.getProperty("dburl");
user = prop.getProperty("user");
password = prop.getProperty("password");
}
private ConnectionFactory() {
}
public static ConnectionFactory getInstance() {
return factory;
}
public Connection makeConnection() {
try {
Class.forName(driver);
conn = DriverManager.getConnection(dburl, user, password);
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
}
JDBC.entity:
package JDBC.entity;
public abstract class IdEntity {
protected int id;
public int getId() {
return id;
}
public int setId(int id) {
return this.id = id;
}
}
package JDBC.entity;
public class User extends IdEntity {
private String name;
private String password;
private String emial;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmial() {
return emial;
}
public void setEmial(String emial) {
this.emial = emial;
}
@Override
public String toString() {
return "User [name=" + name + ", password=" + password + ", "
+ "emial=" + emial + ", id=" + id + "]";
}
}
package JDBC.entity;
public class Address extends IdEntity{
private String city;
private String country;
private int userId;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public int getUserId() {
return userId;
}
public void setUserId(int i) {
this.userId = i;
}
@Override
public String toString() {
return "Address [city=" + city + ", country=" + country + ", "
+ "userId=" + userId + ", id=" + id + "]";
}
}
JDBC.test:
package JDBC;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import JDBC.entity.Address;
import JDBC.entity.User;
import JDBC.util.ConnectionFactory;
public class JDBCtest {
public static void main(String[] args) throws SQLException {
ConnectionFactory cf = ConnectionFactory.getInstance();
Connection conn = cf.makeConnection();
String sql_user = "SELECT * FROM tbl_user";
Statement stat = conn.createStatement();
PreparedStatement ps = null;
Address address = new Address();
User user = new User();
try {
stat.executeQuery(sql_user);
ResultSet re_user = stat.getResultSet();
String sql_address = "SELECT * FROM tbl_address WhERE user_id = ?";
while(re_user.next()){
user.setPassword(re_user.getString("password"));
user.setId(re_user.getInt("id"));
user.setName(re_user.getString("name"));
user.setEmial(re_user.getString("email"));
System.out.println(user.toString());
ps = conn.prepareStatement(sql_address);
ps.setInt(1, user.getId());
ps.execute();
ResultSet re_address = ps.getResultSet();
if(re_address.next()) {
address.setId(re_address.getInt("id"));
address.setCity(re_address.getString("city"));
address.setCountry(re_address.getString("country"));
address.setUserId(re_address.getInt("user_id"));
System.out.println(address.toString());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
程式執行結果:
Address [city=beijing, country=china, userId=1, id=1]
User [name=xiaozhang, password=123456, [email protected], id=2]
Address [city=tianjing, country=china, userId=2, id=2]
相關推薦
Java學習筆記(5)JDBC
JDBC簡介 JDBC簡介: JDBC代表Java資料庫連線(**J**ava **D**ata**b**ase **C**onnectivity),它是用於Java程式語言和資料庫之間的資料庫無關連線的標準Java API,換句話說:JDBC是用於在J
JAVA學習筆記(5)物件和類(上)
1. 面向物件程式設計(OOP)就是使用物件進行程式設計。物件有自己的特性,狀態和行為。物件的狀態是由具有當前值得資料域(又稱屬性)的集合構成。物件的行為是方法的集合定義的。呼叫物件的一個方法就是要求物件執行一次任務。 2. 類是定義同一型別
java學習筆記(5)
第五章 面向物件基礎 一、 題目 1. 什麼是物件?如何建立物件? 類是面嚮物件語言中最重用的一種資料型別,類宣告的變數稱為物件。 建立一個物件包括對物件的宣告和為宣告的物件分配記憶體兩個步驟 假設我們在函式中寫了如下這個簡單的語句: S
Java學習筆記(5):3.面向物件之方法詳解
方法是類或物件的行為特徵的抽象,方法是類或物件最重要的組成成分。但從功能上看,方法完全類似於傳統結構化程式設計裡的函式。值得指出的是,Java裡的方法不能獨立存在,所有的方法必須定義在類裡。方法在邏輯上要麼屬於類,要麼屬於物件。 1.方法的所屬性 永遠不要把方法當成
Java核心技術 卷I 基礎知識 學習筆記(5)
參考:Java核心技術 卷I 基礎知識 反射庫提供了一個非常豐富且精心設計的工具集,以便編寫能夠動態操縱Java程式碼的程式。這項功能被大量地應用與JavaBeans中,它是Java元件的體系結構。 能夠分析類能力的程式成為反射。反射機制的功能極其強大,在下面可以看到,反射機制
Java學習筆記(七):JDBC
JDBC簡介 JDBC(Java Database Connected) 四種Java資料庫操作形式: 1.JDBC-ODBC橋接技術(不用); 2.JDBC直接連線; 3.JDBC網路連線; 4.模擬指定資料庫的通訊協議自己編寫資料庫操作。
java學習筆記(5-基礎語法練習題)
1.鍵盤錄入月份,輸出對應的季節: 基礎版本 package daigua4; import java.util.Scanner; /* * 根據輸入的月份,輸出對應的季節 * */ public class MonthToSeason { public static void main(S
Java學習筆記(12)Spring JDBC框架和事務管理
Spring JDBC框架 JDBC框架概述: 在使用普通的 JDBC 資料庫時,就會很麻煩的寫不必要的程式碼來處理異常,開啟和關閉資料庫連線等。但 Spring JDBC 框架負責所有的低層細節,從開始開啟連線,準備和執行 SQL 語句,處理異常,處理
【Java】「深入理解Java虛擬機」學習筆記(5)- 類加載
一次 some img 不同的 各路 轉換 準備 自己 綁定 C/C++在編譯時需要進行連接,而Java的類加載、連接和初始化是在運行時完成的。 圖 類的生命周期 圖中解析的過程不一定在準備和初始化之間,也可以在初始化之後再開始,以支持Java
JAVA學習筆記(1)——a++與++a的區別
col int 演示 opera 解析 代碼 數據 ++i div 需求:此博客用於解釋i++與++i的區別。 過程: 1、名稱解釋 ++:自增,即在原有數據基礎上+1,再賦給原有數據。 2、程序演示 (1)代碼: 1 class OperateDemo 2 { 3
Swift學習筆記(5):集合類型
nbsp roc 三種 一個 刪除指定元素 edge 空值 port 自定義 目錄: 數組:Array 集合:Set 字典:Dictionary Swift提供Array(有序集合數據)、Set(無序無重復集合)和Dictionary(無序鍵值對集合)三
JAVA學習筆記(三)
byte repl efi ber 時間 clas 區分大小寫 增強for size @SuppressWarnings("resource")是用來壓制資源泄露警告的。比如使用io類,最後沒有關閉。Set集合特點:1)無序,不隨機2)元素唯一3)沒下標註意:Collect
java學習筆記(二)圖形用戶接口
star strong per getwidth cep runnable graphics s2d gb2 這個學期主要放在ACM比賽上去了,比賽結束了。不知不覺就15周了,這周就要java考試了,復習一下java吧。java的學習的目的還是讓我們學以致用,讓我們可以
bootstrap 學習筆記(5)---- 圖片和響應式工具
-h thumb ima ble resp 圓角 rim ucc spl (一)響應式圖片: 在 Bootstrap 版本 3 中,通過為圖片添加 .img-responsive 類可以讓圖片支持響應式布局。其實質是為圖片設置了 max-width: 100%;、 heig
學習筆記(5)---數學運算
mat tla fix bsp matlab 循環 支持 -- oot 一.開n次方 比如-8的立方根,用nthroot(-8,-3),不建議用(-8)^(1/3) 二. 乘除 向0取整數:clear all;clc;fix(7/2)ans = 3-----------
QT學習筆記(5) 菜單欄、工具欄、窗口、對話框
let qlabel rman 運行 內存空間 介紹 edi left setw 本程序主要介紹了以下幾種常用控件的使用方法: (1)菜單欄、工具欄 (2)核心控件、狀態欄、浮動窗口 (3)模態窗口、非模態窗口 (4)標準對話框、文件對話框 代碼如下: mainwindow
Java學習筆記(二)-------String,StringBuffer,StringBuilder區別以及映射到的同步,異步相關知識
ringbuf 等待 java學習筆記 java學習 單線程 回復 改變 hashtable ble 1. String是不可變類,改變String變量中的值,相當於開辟了新的空間存放新的string變量 2. StringBuffer 可變的類,可以通過append方法改
Hibernate學習筆記(5)---Query接口
center 結束 mce factory rst lis 聚集 數據庫 ber Hibernate中具有三種檢索方式(HQL,QBC,SQL) Query接口 一個查詢接口,用於向數據庫中查詢對象。並控制執行查詢的過程。Query接口內封裝了一個HQL查詢語句。 舉個栗子
java學習筆記(四):import語法
employee sign cnblogs java 調用 變量賦值 temp 職位 求職 Import 語法是給編譯器尋找特定類的適當位置的一種方法。 創建一個Employee 類,包括四個實體變量姓名(name),年齡(age),職位(designation)和薪水(s
java學習筆記(六):變量類型
animal 單獨使用 div 位置 fin strong pub 局部變量 變量聲明 java一共三種變量: 局部變量(本地變量):方法調用時創建,方法結束時銷毀 實例變量(全局變量):類創建時創建,類銷毀時銷毀 類變量(靜態變量):程序啟動是創建,程序銷毀時銷毀