文件首頁
MySQL Connector/J 開發人員指南
相關文件 下載本手冊
PDF (美式信紙) - 1.2Mb
PDF (A4) - 1.2Mb


MySQL Connector/J 開發人員指南  /  Connector/J 參考  /  JDBC API 實作注意事項

6.4 JDBC API 實作注意事項

MySQL Connector/J 作為 JDBC API 的嚴格實作,通過了 Oracle 公開提供的 JDBC 相容性測試套件中的所有測試。JDBC 規格在某些功能的實作方式上具有彈性。本節將詳細說明在介面層級可能影響您使用 MySQL Connector/J 編寫應用程式的方式的實作決策。

  • BLOB

    您可以使用屬性 emulateLocators=true 將其新增至 JDBC URL,來使用定位器模擬 BLOB。使用此方法,驅動程式將延遲載入實際的 BLOB 資料,直到您擷取其他資料,然後才在 BLOB 資料流上使用擷取方法 (getInputStream()getBytes() 等)。

    您必須使用資料行的資料行別名,以實際 BLOB 名稱作為資料行的值,例如

    SELECT id, 'data' as blob_data from blobtable

    您也必須遵循下列規則

    • SELECT 只能參考一個資料表。資料表必須具有主索引鍵

    • SELECT 必須將原始 BLOB 資料行名稱 (指定為字串) 別名為替代名稱。

    • SELECT 必須涵蓋構成主索引鍵的所有資料行。

    BLOB 實作不允許就地修改 (它們是複本,如 DatabaseMetaData.locatorsUpdateCopies() 方法所報告)。因此,請使用對應的 PreparedStatement.setBlob()ResultSet.updateBlob() (如果為可更新結果集) 方法將變更儲存回資料庫。

  • 連線

    isClosed() 方法不會對伺服器執行 ping 操作,以判斷其是否可用。根據 JDBC 規格,只有在連線上呼叫 closed() 時,它才會傳回 true。如果您需要判斷連線是否仍然有效,請發出簡單的查詢,例如 SELECT 1。如果連線不再有效,驅動程式將擲回例外狀況。

  • DatabaseMetaData

    只有從 InnoDB 資料表才能取得外部索引鍵資訊 (getImportedKeys()/getExportedKeys()getCrossReference())。驅動程式使用 SHOW CREATE TABLE 來擷取此資訊,因此,如果任何其他儲存引擎新增對外部索引鍵的支援,驅動程式也會透明地支援它們。

  • PreparedStatement

    Connector/J 實作了預備陳述式的兩個變體:用戶端和伺服器端預備陳述式。預設會使用用戶端預備陳述式,因為早期的 MySQL 版本不支援預備陳述式功能,或其實作有問題。當伺服器支援伺服器端預備陳述式時,將會使用伺服器端預備陳述式和二進位編碼的結果集。若要啟用伺服器端預備陳述式的使用,請設定 useServerPrepStmts=true

    使用 setBinaryStream()setAsciiStream()setUnicodeStream()setCharacterStream()setNCharacterStream()setBlob()setClob()setNCLob() 設定的大型參數時,請小心使用伺服器端預備陳述式。若要使用變更為非大型參數的任何大型參數重新執行陳述式,請呼叫 clearParameters() 並再次設定所有參數。原因如下

    • 在伺服器端預備陳述式和用戶端模擬期間,只有在呼叫 PreparedStatement.execute() 時才會交換大型資料。

    • 完成此作業後,用於讀取用戶端資料的串流將會關閉 (根據 JDBC 規格),且無法再次讀取。

    • 如果參數從大型變更為非大型,驅動程式必須重設預備陳述式的伺服器端狀態,以允許正在變更的參數取代先前的大型值。這會移除已傳送至伺服器的所有大型資料,因此需要使用 setBinaryStream()setAsciiStream()setUnicodeStream()setCharacterStream()setNCharacterStream()setBlob()setClob()setNCLob() 方法重新傳送資料。

    因此,若要將參數的類型變更為非大型類型,您必須呼叫 clearParameters() 並再次設定預備陳述式的所有參數,才能重新執行它。

  • ResultSet

    預設情況下,會完整擷取結果集並將其儲存在記憶體中。在大多數情況下,這是最有效率的運作方式,而且由於 MySQL 網路通訊協定的設計,更容易實作。如果您使用具有大量資料列或大型值的結果集,且無法在您的 JVM 中配置所需的記憶體堆積空間,您可以指示驅動程式一次將結果串流回一個資料列。

    若要啟用此功能,請以下列方式建立 Statement 執行個體

    stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
                  java.sql.ResultSet.CONCUR_READ_ONLY);
    stmt.setFetchSize(Integer.MIN_VALUE);

    具有提取大小為 Integer.MIN_VALUE 的僅限轉送、唯讀結果集組合,可作為驅動程式逐列串流結果集的訊號。之後,使用陳述式建立的任何結果集都將逐列擷取。

    此方法有一些注意事項。您必須讀取結果集中的所有資料列 (或將其關閉),才能對連線發出任何其他查詢,否則將會擲回例外狀況。

    這些陳述式保留的鎖定最早可以在陳述式完成時釋放 (無論它們是 MyISAM 資料表層級鎖定,還是其他儲存引擎 (例如 InnoDB) 中的資料列層級鎖定)。

    如果陳述式在交易的範圍內,那麼當交易完成時(這表示陳述式需要先完成)鎖定會被釋放。如同大多數其他資料庫,陳述式必須等到所有陳述式上等待的結果被讀取,或是陳述式的作用結果集關閉之後才會完成。

    因此,如果使用串流結果,如果您想要維持對產生結果集的陳述式所參考的資料表的並行存取,請盡快處理它們。

    另一個替代方案是使用基於游標的串流,每次擷取設定數量的列。這可以透過將連線屬性 useCursorFetch 設定為 true,然後呼叫 setFetchSize(int),其中 int 是每次要擷取的列數來完成。

    conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1/?useCursorFetch=true", "user", "s3cr3t");
    stmt = conn.createStatement();
    stmt.setFetchSize(100);
    rs = stmt.executeQuery("SELECT * FROM your_table_here");
  • 陳述式

    Connector/J 包含對 Statement.cancel()Statement.setQueryTimeout() 的支援。兩者都需要單獨的連線來發出 KILL QUERY 陳述式。在 setQueryTimeout() 的情況下,實作會建立一個額外的執行緒來處理逾時功能。

    注意

    由於目前沒有辦法取消由於逾時到期而正在取消查詢的執行緒並使其拋出例外,因此 setQueryTimeout() 無法取消陳述式可能會以 RuntimeException 的形式表現出來,而不是靜默失敗。

    MySQL 不支援 SQL 游標,而 JDBC 驅動程式不模擬它們,因此 setCursorName() 沒有任何效果。

    Connector/J 也提供兩個額外的方法

    • setLocalInfileInputStream() 設定一個 InputStream 實例,該實例將用於將資料傳送到 MySQL 伺服器,以用於 LOAD DATA LOCAL INFILE 陳述式,而不是表示作為陳述式參數給定的路徑的 FileInputStreamURLInputStream

      在執行 LOAD DATA LOCAL INFILE 陳述式時,將會讀取此串流直到完成,並會由驅動程式自動關閉,因此在每次呼叫 execute*() 之前需要重設此串流,此呼叫會導致 MySQL 伺服器請求資料來滿足對 LOAD DATA LOCAL INFILE 的請求。

      如果此值設定為 NULL,驅動程式將會還原為根據需要使用 FileInputStreamURLInputStream

    • getLocalInfileInputStream() 傳回將用於傳送資料以回應 LOAD DATA LOCAL INFILE 陳述式的 InputStream 實例。

      如果沒有使用 setLocalInfileInputStream() 設定此串流,此方法會傳回 NULL