# 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型別

<br>
---
# 模組20 - DAO設計模式
## ==DAO設計模式==
- 針對資料庫表格存取會設計一個Data Access Object(DAO)類別來對應
1. 此DAO類別封裝JDBC的資料庫存取程式碼的實作,應用程式若需要存取資料庫時,一律透過此DAO來處理
- 通常不同廠商提供的資料庫,除了標準的SQL指令外,有些存取會依資料庫的不同而有所不同
2. 若設計目的是更換資料庫時,==只需更換DAO即可==,而應用程式無需變更
- 針對每一個DAO類別設計一個DAO介面來對應
-> 此DAO介面負責定義方法 ==(對此表格各種資料存取的操作,CRUD)==
<br>
