JDBC

Apps Script 可以透過 JDBC 服務連線至外部資料庫,這項服務是標準 Java Database Connectivity 技術的包裝函式。JDBC 服務支援 MySQL 適用的 Google Cloud SQL、MySQL、Microsoft SQL Server 和 Oracle 資料庫。

如要使用 JDBC 更新外部資料庫,指令碼必須開啟資料庫連線,然後傳送 SQL 陳述式來進行變更。

Google Cloud SQL 資料庫

Google Cloud SQL 可讓您建立位於 Google 雲端的關聯資料庫。請注意,Cloud SQL 可能會根據您的用量產生費用。

您可以按照 Cloud SQL 快速入門中的步驟建立 Google Cloud SQL 執行個體。

建立 Google Cloud SQL 連線

使用 Apps Script 的 JDBC 服務,有兩種方法可以建立與 Google Cloud SQL 資料庫的連線:

以下說明這些方法。兩者皆有效,但第二種方法需要您授權一組 IP 範圍,才能存取資料庫。

這個方法會使用 Jdbc.getCloudSqlConnection(url) 方法,建立與 Google Cloud SQL MySQL 執行個體的連線。資料庫網址的格式為 jdbc:google:mysql://subname,其中 subnameGoogle Cloud 控制台中 Cloud SQL 執行個體「總覽」頁面所列的 MySQL 執行個體連線名稱

如要連線至 Cloud SQL SQL Server,請參閱 Jdbc.getConnection(url)

使用 Jdbc.getConnection(url)

如要使用這個方法,您必須授權特定的無類別跨網域路由 (CIDR) IP 位址範圍,讓 Apps Script 伺服器能夠連線至您的資料庫。執行指令碼前,請完成下列步驟:

  1. 在 Google Cloud SQL 執行個體中,從這個資料來源授權 IP 範圍,一次一個。

  2. 複製指派給資料庫的網址,其格式應為 jdbc:mysql:subname

授權這些 IP 範圍後,您就可以使用其中一個 Jdbc.getConnection(url) 方法和上述複製的網址,建立連線至 Google Cloud SQL 執行個體的連線。

其他資料庫

如果您已擁有自己的 MySQL、Microsoft SQL Server 或 Oracle 資料庫,可以透過 Apps Script 的 JDBC 服務連線。

建立其他資料庫連線

如要使用 Apps Script JDBC 服務建立資料庫連線,您必須在資料庫設定中授權 這個資料來源的 IP 範圍。

這些許可清單完成後,您就可以使用其中一個 Jdbc.getConnection(url) 方法和資料庫的網址,建立資料庫連線。

程式碼範例

以下範例程式碼假設您要連線至 Google Cloud SQL 資料庫,並使用 Jdbc.getCloudSqlConnection(url) 方法建立資料庫連線。對於其他資料庫,您必須使用 Jdbc.getConnection(url) 方法建立資料庫連線。

如要進一步瞭解 JDBC 方法,請參閱 JDBC 的 Java 說明文件

建立資料庫、使用者和資料表

大多數開發人員都會使用 MySQL 指令列工具建立資料庫、使用者和資料表。不過,您也可以在 Apps Script 中執行相同的操作,如下所示。建議您至少建立一個其他使用者,這樣指令碼就不會一律以 root 的身份連線至資料庫。

service/jdbc.gs
/**
 * Create a new database within a Cloud SQL instance.
 */
function createDatabase() {
  try {
    const conn = Jdbc.getCloudSqlConnection(instanceUrl, root, rootPwd);
    conn.createStatement().execute('CREATE DATABASE ' + db);
  } catch (err) {
    // TODO(developer) - Handle exception from the API
    console.log('Failed with an error %s', err.message);
  }
}

/**
 * Create a new user for your database with full privileges.
 */
function createUser() {
  try {
    const conn = Jdbc.getCloudSqlConnection(dbUrl, root, rootPwd);

    const stmt = conn.prepareStatement('CREATE USER ? IDENTIFIED BY ?');
    stmt.setString(1, user);
    stmt.setString(2, userPwd);
    stmt.execute();

    conn.createStatement().execute('GRANT ALL ON `%`.* TO ' + user);
  } catch (err) {
    // TODO(developer) - Handle exception from the API
    console.log('Failed with an error %s', err.message);
  }
}

/**
 * Create a new table in the database.
 */
function createTable() {
  try {
    const conn = Jdbc.getCloudSqlConnection(dbUrl, user, userPwd);
    conn.createStatement().execute('CREATE TABLE entries ' +
      '(guestName VARCHAR(255), content VARCHAR(255), ' +
      'entryID INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(entryID));');
  } catch (err) {
    // TODO(developer) - Handle exception from the API
    console.log('Failed with an error %s', err.message);
  }
}

寫入資料庫

以下範例說明如何將單一記錄寫入資料庫,以及如何寫入 500 筆記錄的批次。批次處理對於大量作業至關重要。

請注意參數化陳述式的使用方式,其中變數以 ? 表示。為避免發生 SQL 注入攻擊,您應使用參數化陳述式來轉義所有使用者提供的資料。

service/jdbc.gs
/**
 * Write one row of data to a table.
 */
function writeOneRecord() {
  try {
    const conn = Jdbc.getCloudSqlConnection(dbUrl, user, userPwd);

    const stmt = conn.prepareStatement('INSERT INTO entries ' +
      '(guestName, content) values (?, ?)');
    stmt.setString(1, 'First Guest');
    stmt.setString(2, 'Hello, world');
    stmt.execute();
  } catch (err) {
    // TODO(developer) - Handle exception from the API
    console.log('Failed with an error %s', err.message);
  }
}

/**
 * Write 500 rows of data to a table in a single batch.
 */
function writeManyRecords() {
  try {
    const conn = Jdbc.getCloudSqlConnection(dbUrl, user, userPwd);
    conn.setAutoCommit(false);

    const start = new Date();
    const stmt = conn.prepareStatement('INSERT INTO entries ' +
      '(guestName, content) values (?, ?)');
    for (let i = 0; i < 500; i++) {
      stmt.setString(1, 'Name ' + i);
      stmt.setString(2, 'Hello, world ' + i);
      stmt.addBatch();
    }

    const batch = stmt.executeBatch();
    conn.commit();
    conn.close();

    const end = new Date();
    console.log('Time elapsed: %sms for %s rows.', end - start, batch.length);
  } catch (err) {
    // TODO(developer) - Handle exception from the API
    console.log('Failed with an error %s', err.message);
  }
}

從資料庫讀取

本範例示範如何從資料庫讀取大量記錄,並視需要對結果集進行迴圈。

service/jdbc.gs
/**
 * Read up to 1000 rows of data from the table and log them.
 */
function readFromTable() {
  try {
    const conn = Jdbc.getCloudSqlConnection(dbUrl, user, userPwd);
    const start = new Date();
    const stmt = conn.createStatement();
    stmt.setMaxRows(1000);
    const results = stmt.executeQuery('SELECT * FROM entries');
    const numCols = results.getMetaData().getColumnCount();

    while (results.next()) {
      let rowString = '';
      for (let col = 0; col < numCols; col++) {
        rowString += results.getString(col + 1) + '\t';
      }
      console.log(rowString);
    }

    results.close();
    stmt.close();

    const end = new Date();
    console.log('Time elapsed: %sms', end - start);
  } catch (err) {
    // TODO(developer) - Handle exception from the API
    console.log('Failed with an error %s', err.message);
  }
}

關閉連線

指令碼執行完畢後,JDBC 連線會自動關閉。(請注意,即使發出呼叫的 HTML 服務網頁仍處於開啟狀態,單一 google.script.run 呼叫也算是完整執行作業)。

不過,如果您知道在指令碼結束前,已完成使用連線、陳述式或結果集,建議您呼叫 JdbcConnection.close()JdbcStatement.close()JdbcResultSet.close(),手動關閉這些項目。

顯示警告或提示對話方塊也會終止任何已開啟的 JDBC 連線。不過,其他顯示 UI 元素 (例如自訂選單或對話方塊,以及含有自訂內容的側邊欄) 則不受影響。

Google、Google Workspace 和其他相關符號及標誌均為 Google LLC 的商標。所有其他公司名稱和產品名稱則為關聯企業的商標。