---
# System prepended metadata

title: JDBC 小吳 20210426
tags: [JDBC]

---

# 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)

