משחקי JDBC

הגרסאות 1.0 ו-1.1 של פרוטוקול האבטחה TLS מושבתות. כדי ליצור חיבורים, צריך להשתמש ב-TLS 1.2 או בגרסה מאובטחת יותר.

‫Google Apps Script יכול להתחבר למסדי נתונים חיצוניים באמצעות שירות JDBC, שהוא עטיפה של טכנולוגיית Java Database Connectivity (קישוריות למסדי נתונים ב-Java) הרגילה. שירות JDBC תומך במסדי נתונים של Google Cloud SQL ל-MySQL, ‏ MySQL, ‏ Microsoft SQL Server, ‏ Oracle ו-PostgreSQL.

אם הגיליון האלקטרוני גדל יותר מדי או שאתם נתקלים בבעיות של זמן קצוב לתפוגה בחישובים מורכבים, העברת הנתונים למסד נתונים חיצוני יכולה לשפר באופן משמעותי את הביצועים והמהימנות.

כדי לעדכן מסד נתונים חיצוני באמצעות JDBC, הסקריפט צריך לפתוח חיבור למסד הנתונים ואז לבצע שינויים על ידי שליחת משפטי SQL.

מסדי נתונים של Google Cloud SQL

Google Cloud SQL מאפשר ליצור מסדי נתונים יחסיים שמתארחים בענן של Google. יכול להיות שתחויבו על השימוש ב-Cloud SQL.

יוצרים מכונה של Google Cloud SQL לפי השלבים שמפורטים במדריך למתחילים של Cloud SQL.

יצירת חיבורים ל-Google Cloud SQL

יש שתי דרכים ליצור חיבור למסד נתונים של Google Cloud SQL באמצעות שירות JDBC של Apps Script:

שתי השיטות תקפות, אבל בשיטה השנייה צריך לאשר קבוצה של טווחי כתובות IP כדי לגשת למסד הנתונים.

השיטה הזו יוצרת חיבור למכונת MySQL ב-Google Cloud SQL באמצעות השיטה Jdbc.getCloudSqlConnection. כתובת ה-URL של מסד הנתונים היא מהצורה jdbc:google:mysql://subname, כאשר subname הוא שם החיבור של המופע ב-MySQL שמופיע בדף Overview של מופע Cloud SQL ב-מסוף Google Cloud.

כדי להתחבר ל-Cloud SQL SQL Server, אפשר לעיין במאמר בנושא Jdbc.getConnection.

שימוש ב-Jdbc.getConnection

כדי להשתמש בשיטה הזו, צריך לתת הרשאה לטווחי כתובות IP מסוימים של Classless Inter-Domain Routing‏ (CIDR) כדי שהשרתים של Apps Script יוכלו להתחבר למסד הנתונים שלכם. לפני שמריצים את הסקריפט, צריך לבצע את השלבים הבאים:

  1. במופע Google Cloud SQL, מאשרים את טווחי כתובות ה-IP, כל אחד בנפרד ממקור הנתונים הזה.

  2. מעתיקים את כתובת ה-URL שהוקצתה למסד הנתונים. היא צריכה להיות בפורמט jdbc:mysql:subname.

אחרי שמאשרים את טווחי כתובות ה-IP האלה, יוצרים חיבורים למופע Google Cloud SQL באמצעות אחת מהשיטות של Jdbc.getConnection וכתובת ה-URL שהעתקתם קודם.

מסדי נתונים אחרים

אם כבר יש לכם מסד נתונים משלכם ב-MySQL, ‏ Microsoft SQL Server, ‏ Oracle או PostgreSQL, תוכלו להתחבר אליו באמצעות שירות JDBC של Apps Script.

יצירת חיבורים למסדי נתונים אחרים

כדי ליצור חיבור למסד נתונים באמצעות שירות JDBC של Apps Script, צריך לאשר בנתוני מסד הנתונים טווחי כתובות IP ממקור הנתונים הזה.

שירות ה-JDBC יכול להתחבר רק ליציאות 1025 ומעלה. מוודאים שמסד הנתונים לא מוגדר לשימוש ביציאה נמוכה יותר.

אחרי שיוצרים את רשימות ההיתרים האלה, יוצרים חיבור למסד הנתונים באמצעות אחת מהשיטות של Jdbc.getConnection וכתובת ה-URL של מסד הנתונים.

קוד לדוגמה

הקוד לדוגמה הבא מניח שאתם מתחברים למסד נתונים של Google Cloud SQL, ויוצר חיבורים למסד הנתונים באמצעות השיטה Jdbc.getCloudSqlConnection. במסדי נתונים אחרים צריך להשתמש בשיטה Jdbc.getConnection כדי ליצור חיבורים למסד הנתונים.

למידע נוסף על שיטות JDBC, אפשר לעיין במסמכי התיעוד של Java בנושא JDBC.

יצירת מסד נתונים, משתמש וטבלה

רוב המפתחים משתמשים בכלי שורת פקודה של 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, צריך להשתמש בהצהרות עם פרמטרים כדי לבצע escape לכל הנתונים שסופקו על ידי המשתמש.

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);
  }
}

/**
 * Write 500 rows of data to a table in a single batch.
 * Recommended for faster writes
 */
function writeManyRecordsUsingExecuteBatch() {
  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 (?, ?)",
    );
    const params = [];
    for (let i = 0; i < 500; i++) {
      params.push([`Name ${i}`, `Hello, world ${i}`]);
    }

    const batch = stmt.executeBatch(params);
    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);
  }
}

/**
 * Read up to 1000 rows of data from the table and log them.
 * Recommended for faster reads
 */
function readFromTableUsingGetRows() {
  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();
    const getRowArgs = [];
    for (let col = 0; col < numCols; col++) {
      getRowArgs.push(`getString(${col + 1})`);
    }
    const rows = results.getRows(getRowArgs.join(","));
    for (let i = 0; i < rows.length; i++) {
      console.log(rows[i].join("\t"));
    }

    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 נסגרים אוטומטית כשסקריפט מסיים את ההרצה. (קריאות google.script.run בודדות נספרות כהפעלה מלאה, גם אם דף שירות ה-HTML שממנו בוצעה הקריאה נשאר פתוח).

עם זאת, אם אתם יודעים שסיימתם להשתמש בחיבור, בהצהרה או בערכת תוצאות לפני סוף הסקריפט, אתם יכולים לסגור אותם באופן ידני על ידי קריאה ל-JdbcConnection.close, ל-JdbcStatement.close או ל-JdbcResultSet.close.

הצגה של תיבת דו-שיח של התראה או בקשה גורמת גם לסגירה של כל חיבורי ה-JDBC הפתוחים. עם זאת, רכיבי ממשק משתמש אחרים שמוצגים – כמו תפריטים מותאמים אישית, תיבות דו-שיח וסרגלי צד עם תוכן מותאם אישית – לא נכללים בהגדרה הזו.

‫Google,‏ Google Workspace וסימנים וסמלי לוגו קשורים הם סימנים מסחריים של Google LLC. כל שמות החברות והמוצרים האחרים הם סימנים מסחריים של החברות שאליהן הם משויכים.