# JDBC 小吳 20210426 ###### tags: `JDBC` # 模組10 - ResultSet進階操作 ## 游標進階操作 (JDBC 2.0) - JDBC 2.0對ResultSet做了許多加強,允許更彈性的移動游標與資料更新等進階操作 - 建立Statement物件時進行設定: ``` - Statement createStatement(int resultSetType, int resultSetConcurrency) - PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) ``` - 驅動程式必須能夠支援,否則會產生Runtime Exception - ==不是所有驅動程式都支援== - 相關參數 (都是在ResultSet介面已定義好的static final的整數常數): 1. ==ResultSetType== - `TYPE_FORWARD_ONLY` : 只能前進 - `TYPE_SCROLL_INSENSITIVE` : 可前後移動,不反應資料修改 - `TYPE_SCROLL_SENSITIVE` : 可前後移動,反應資料修改 2. ==ResultSetConcurrency== - `CONCUR_READ_ONLY` : 資料為唯讀 - `CONCUR_UPDATABLE` : 資料可異動,如新增、修改與刪除) <br> - 若沒設定,預設為 ==TYPE_FORWARD_ONLY & CONCUR_READ_ONLY== <br> ##### 備註 1. INSENSITIVE跟SENSITIVE也須配合資料庫是否有此功能的支援 2. 反應資料修改: 若是ResultSet使用期間,資料有發生異動時,不需要再查詢一次,即可得到更新的結果 <br> --- # 模組11 - Metadata介紹 ## ==Metadata介紹== ## 中繼資料 (Metadata) - 此名詞源自於1969年,由Jack E. Myers提出 "關於資料的資料" (data about data),後被定義為 ==描述資料的資料== 而延用至今,不過各方定義紛紛出現,現在主要有分成以下三種metadata: 1. 描敘性metadata 2. 結構性metadata 3. 管理性metadata - 用書本為例,對應上面三種metadata <br> --- ## ==JDBC Metadata== <br> - 透過 ==Connection 的 getMetaData== 方法取得DatabaseMetaData物件,而DatabaseMetaData可取得資料庫相關資訊,為研發人員用來寫獨立於資料庫的驅動程式和開發工具 - 透過 ==ResultSet 的 getMetaData== 方法即可取得ResultSetMetaData物件,也是應用程式開發人員較常用到的metadata,因為可以獲取查詢資料列以外的相關資訊 - ResultSetMetaData常用方法: 1. `int getColumnCount()`:取得欄位數 2. `String getColumnName(int col)`:取得欄位名 3. `String getColumnTypeName(int col)`:取得欄位在DBMS所使用的SQL type的名稱 4. `String getTableName(int col)`:取得欄位所屬的表格名稱 5. `int isNullable(int col)`:欄位能否為null <br> --- # 模組12 - 批次更新 ## ==批次更新== ## Batch Update - ==批次更新(Batch Update)適用於對資料庫進行大量更新的行為==,將要執行的SQL指令一次收集完畢後再送出,效能會比一次一次送出SQL指令要來得更好 - 透過`addBatch()`方法收集SQL指令後,將結合成一句SQL指令,再利用`executeBatch()`方法送出,其中執行SQL產生的例外為BatchUpdateException - 只適用於更新(如新增、修改或刪除),對於查詢功能無法支援 - 需注意各廠商資料庫是否對批次更新的支援,可藉由`DatabaseMetaData的supportsBatchUpdates()`得知結果 - MySQL要使用批次更新的話,++連結的URL需做額外設定++ ==(參考範例Util.java裡的說明)== <br> --- # 模組13 - JDBC例外處理 ## ==JDBC例外處理== ## SQLException相關 - SQLException為受檢例外 (Checked Exception) 1. `getMessage()` –> 足以應付大部份情況,訊息是驅動程式在執行產生例外時加入 2. `getSQLState()` -> String資料,++不常用,因為各家資料庫的狀態說明與錯誤代碼都不一樣++ 3. `getErrorCode()` -> int資料,++不常用,因為各家資料庫的狀態說明與錯誤代碼都不一樣++ 4. `getNextException()` <br> - 在JDBC4.0時,SQLException新增了幾個以Throwable為建構子參數的建構子,就可以將任何其它類型的例外也包裝成SQLException再做後續處理 <br> - 同上,SQLException也同時實作了`Iterable<Throwable>`介面,可以搭配for-each取出 <br> --- ## SQLWarning相關 - SQLWarning 與 DataTruncation 1. SQLWarning不會中止程式執行,也不常出現 2. Connection、ResultSet與Statement相關都可能會有SQLWarning 3. 可透過`getWarnings()`取得SQLWarning物件 4. 訊息取得方式也跟SQLException相同 - DataTruncation is a SQLWarning,主要就是 ==資料截斷的問題發生==,例如對於浮點數欄位卻以整數方式取得,雖不至於導致程式發生例外,但因為++資料取得的不完整,就是屬於一種警告++ <br> --- # 模組14 - BLOB & CLOB ## ==BLOB與CLOB== - ==Binary Large OBject== : 讓我們可以將檔案(如圖片、影音資料等)存入資料庫欄位裡,單筆最高可達4GB大小 - ==Character Large OBject== : 與BLOB不同的是,可以用CLOB儲存大量的文字資料,最高大小也可至4GB - SQL指令對以上兩種資料類型的支援度還不夠完善,因此常結合程式碼來處理與操作BLOB / CLOB - 需注意的是在 ==創建表格時==,++欄位需先宣告為BLOB / CLOB類型++ - MySQL匯入問題 1. ==BLOB檔== ++問題++:新增資料進入table的BLOB欄位內發生資料過大問題, 錯誤訊息`「Data truncation: Data too long for column ‘image’ at row 1」` ++解決方法++:將BLOB欄位改成較大型別 ``` TINYBLOB : maximum length of 255 bytes BLOB : maximum length of 65,535 bytes MEDIUMBLOB : maximum length of 16,777,215 bytes LONGBLOB : maximum length of 4,294,967,295 bytes ``` <br> 2. ==DB檔== ++問題++: MySQL匯入資料時要注意資料是否過大(例如:圖檔) 可能產生「packet bigger than ‘max_allowed_packet’ bytes」錯誤問題, ++解決方式++: ==Windows==: Windows:將「my.ini」(C:\ProgramData\MySQL\MySQL Server 5.x\my.ini)內容「max_allowed_packet」的值加大,例如改成「max_allowed_packet=500M」(更改完設定一定要重啟MySQL) <br> ==Mac OS==: 修改my.cnf(就是Windows的my.ini)內容「max_allowed_packet」的值加大,例如改成「max_allowed_packet=500M」(更改完設定一定要重啟MySQL) 也可透過Workbench修改下列設定: 1. 開啟Workbench > Server > Options File > Networking > max_allowed_packet > 改成500M 2. 開啟Workbench > Server > Options File > InnoDB > innodb_log_file_size > 改成256M ##### 備註 CLOB 在 MySQL 裡的型別對應叫做 "TEXT" <br> --- ## ==操作CLOB== ## CLOB處理方式 - JDBC API提供了Clob介面給資料庫廠商可以實作 - 相關處理做法: 1. getCharacterStream / setCharacterStream (對Unicode編碼文字處理) 2. getClob / setClob 3. getString / setString -> 最推薦用 4. 結合資料流操作,取得字串資料 - JDBC 4.0時,PreparedStatement新增了setClob(int parameterIndex, Reader reader),改進了使用方法與操作 <br> --- # 模組15 - 資料庫圖片處理 ## ==操作BLOB== ## BLOB處理方式 - JDBC API提供了Blob介面給資料庫廠商可以實作 - 相關處理做法: 1. `getBytes` / `setBytes` -> ++適用於任何Java版本,資料量較不多的操作(100MB以下)++ 2. `getBlob` / `setBlob` -> ++須注意版本問題,適合進行大量資料傳輸++ 3. `getBinaryStream` / `setBinaryStream` -> ++須注意版本問題,適合進行大量資料傳輸++ 4. 結合資料流操作,取得`byte[]`資料 - JDBC 4.0時,PreparedStatement新增了`setBlob(int parameterIndex, InputStream inputStream)`,改進了使用方法與操作 <br> --- # 模組19 - ORM設計模式 ## ==ORM設計介紹== ## 物件 – 關聯式資料庫對映 - 物件 – 關聯式資料庫對映(Object-Relational Mapping) 1. 簡稱ORM或是O/R Mapping 2. 是一種常見的軟體設計模式(design pattern) - ==一個資料庫表格對應一個Java類別,表格欄位對應到此類別的實體變數== 1. 此Java類別稱為Value Object(VO)或Data Transfer Object(DTO),用在client端與server端間傳遞資料 2. 亦即應用程式的Domain Object對應到資料庫的business entity 3. 以 ==Java Bean== 來實作business entity - 對每一個private欄位分別設計一組getter/setter - 此類別實作Serializable介面 - 此類別擁有一個不帶參數的建構子 ##### 備註 1. Value Object(VO): 對應到資料庫表格資料的物件 2. Java bean: Java EE 裡最基礎/根本的一個元件,八字箴言: "包裝資料 重複使用" <br> --- ## Java型別與SQL型別 ![](https://i.imgur.com/WAf0Ql2.png) <br> --- # 模組20 - DAO設計模式 ## ==DAO設計模式== - 針對資料庫表格存取會設計一個Data Access Object(DAO)類別來對應 1. 此DAO類別封裝JDBC的資料庫存取程式碼的實作,應用程式若需要存取資料庫時,一律透過此DAO來處理 - 通常不同廠商提供的資料庫,除了標準的SQL指令外,有些存取會依資料庫的不同而有所不同 2. 若設計目的是更換資料庫時,==只需更換DAO即可==,而應用程式無需變更 - 針對每一個DAO類別設計一個DAO介面來對應 -> 此DAO介面負責定義方法 ==(對此表格各種資料存取的操作,CRUD)== <br> ![](https://i.imgur.com/HRibwB0.png)