שילוב של Spanner עם Spring Data

מודול Spring Data Spanner עוזר לכם להשתמש ב-Spanner בכל אפליקציית Java שמבוססת על Spring Framework.

בדומה לכל המודולים של Spring Data,‏ Spring Data Spanner מספק מודל תכנות מבוסס-Spring ששומר על עקביות ועל יכולת ההתאמה של Spanner. התכונות שלו דומות ל-Spring Data JPA ול-Hibernate ORM, עם הערות שנועדו ל-Spanner. מידע נוסף על השימוש ב-Spring Data JPA עם Spanner זמין במאמר שילוב של Spanner עם Spring Data JPA (ניב GoogleSQL).

אם אתם כבר מכירים את Spring, ‏ Spring Data Spanner יכול להקל עליכם לעבוד עם Spanner באפליקציה שלכם ולצמצם את כמות הקוד שאתם צריכים לכתוב.

בדף הזה מוסבר איך להוסיף את Spring Data Spanner לאפליקציית Java. מידע מפורט על המודול זמין במאמר בנושא Spring Data Spanner.

התקנת המודול

אם משתמשים ב-Maven, צריך להוסיף את Spring Cloud GCP Bill of Materials (BOM) ואת Spring Data Spanner לקובץ pom.xml. התלויות האלה מספקות את רכיבי Spring Data Spanner ל-Spring‏ ApplicationContext:

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>com.google.cloud</groupId>
      <artifactId>spring-cloud-gcp-dependencies</artifactId>
      <version>3.7.7</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-dependencies</artifactId>
      <version>${spring.boot.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

<dependencies>
  <dependency>
    <groupId>com.google.cloud</groupId>
    <artifactId>spring-cloud-gcp-starter-data-spanner</artifactId>
  </dependency>
</dependencies>

צריך גם ליצור חשבון שירות ולהשתמש במפתח של חשבון השירות כדי לבצע אימות באמצעות Google Cloud.

מידע נוסף זמין בהוראות בנושא הגדרת סביבת פיתוח בשפת Java. לא צריך להתקין את Google Cloud ספריית הלקוח ל-Java, כי Spring Boot starter מתקין את ספריית הלקוח באופן אוטומטי.

הגדרת המודול

בקטע הזה מתוארות כמה מהגדרות התצורה הנפוצות ביותר של Spring Data Spanner. רשימה מלאה של ההגדרות מופיעה במאמרי העזרה.

מציינים מופע ומסד נתונים

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

מאפיין (property) תיאור
spring.cloud.gcp.spanner.project-id זה שינוי אופציונלי. מזהה הפרויקט Google Cloud . הפונקציה מחליפה את הערך של spring.cloud.gcp.config.project-id.
spring.cloud.gcp.spanner.instance-id מזהה מכונת Spanner.
spring.cloud.gcp.spanner.database מסד הנתונים שאליו רוצים להתחבר.

מודל נתונים של Spanner

בעזרת Spring Data Spanner, אפשר להשתמש באובייקטים פשוטים של Java (POJO) כדי ליצור מודל של הנתונים שמאוחסנים בטבלאות Spanner.

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

אפשר להשתמש בהערות הבאות כדי ליצור מודל של קשרים פשוטים בין ישויות לבין טבלאות:

הערות לגבי ישויות
@Column(name = "columnName")

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

אם לא מציינים את המאפיין הזה, אסטרטגיית ברירת המחדל למתן שמות ב-Spring Data Spanner ממפה שמות של מאפייני Java‏ camelCase לשמות של עמודות PascalCase. לדוגמה, המאפיין singerId ממופה לשם העמודה SingerId.

@Embedded

מציין שהמאפיין הוא אובייקט מוטמע שיכול להכיל רכיבים של מפתח ראשי. אם המאפיין משמש בפועל כמפתח הראשי, צריך לכלול גם את ההערה @PrimaryKey.

@Interleaved

@Interleaved(lazy = true)

השדה הזה מציין שנכס מסוים מכיל רשימה של שורות שמשולבות בשורה הנוכחית.

כברירת מחדל, Spring Data Spanner מאחזר את השורות המשלבות בזמן יצירת המופע. כדי לאחזר את השורות באופן עצלני כשניגשים למאפיין, משתמשים ב-@Interleaved(lazy = true).

דוגמה: אם לישות Singer יכולות להיות רשומות Album כצאצאים, מוסיפים מאפיין List<Album> לישות Singer. בנוסף, מוסיפים הערה @Interleaved לנכס.

@NotMapped

מציין שמאפיין לא נשמר במסד הנתונים וצריך להתעלם ממנו.

@PrimaryKey

@PrimaryKey(keyOrder = N)

מציין שהמאפיין הוא רכיב של המפתח הראשי, ומזהה את המיקום של המאפיין במפתח הראשי, החל מ-1. ערך ברירת המחדל keyOrder הוא 1.

לדוגמה: @PrimaryKey(keyOrder = 3)

@Table(name = "TABLE_NAME")

הטבלה שהישות מבוססת עליה. כל מופע של הישות מייצג רשומה בטבלה. מחליפים את TABLE_NAME בשם הטבלה.

לדוגמה: @Table(name = "Singers")

אם אתם צריכים ליצור מודלים של קשרים מורכבים יותר, תוכלו לעיין בהפניה ל-Spring Data Spanner כדי לקבל פרטים על הערות אחרות שהמודול תומך בהן.

בדוגמאות הבאות מוצגת דרך אחת ליצור מודל של הטבלאות Singers ו-Albums עבור Spring Data Spanner:

  • בדוגמה של ישויות Singer, יש מאפיין albums עם הערה @Interleaved. המאפיין הזה מכיל רשימה של אלבומים שמשולבים עם הישות Singer. המאפיין הזה מאוכלס באופן אוטומטי על ידי Spring Data Spanner.
  • בדוגמה של ישויות Album, יש מאפיין relatedAlbums שלא מאוחסן ב-Spanner.
import com.google.cloud.spring.data.spanner.core.mapping.Interleaved;
import com.google.cloud.spring.data.spanner.core.mapping.PrimaryKey;
import com.google.cloud.spring.data.spanner.core.mapping.Table;
import java.util.Date;
import java.util.List;


/**
 * An entity and table holding singers.
 */
@Table(name = "Singers")
public class Singer {
  @PrimaryKey
  long singerId;

  String firstName;

  String lastName;

  Date birthDate;

  @Interleaved
  List<Album> albums;
}
import com.google.cloud.spring.data.spanner.core.mapping.NotMapped;
import com.google.cloud.spring.data.spanner.core.mapping.PrimaryKey;
import com.google.cloud.spring.data.spanner.core.mapping.Table;
import java.util.List;

/**
 * An entity class representing an Album.
 */
@Table(name = "Albums")
public class Album {

  @PrimaryKey
  long singerId;

  @PrimaryKey(keyOrder = 2)
  long albumId;

  String albumTitle;

  long marketingBudget;

  @NotMapped
  List<Album> relatedAlbums;

  public Album(long singerId, long albumId, String albumTitle, long marketingBudget) {
    this.singerId = singerId;
    this.albumId = albumId;
    this.albumTitle = albumTitle;
    this.marketingBudget = marketingBudget;
  }
}

שאילתה ושינוי של נתונים

כדי לשלוח שאילתות לנתונים ולשנות אותם באמצעות Spring Data Spanner, אפשר להשיג רכיב מסוג SpannerTemplate, שמטמיע את SpannerOperations. ‫SpannerTemplate מספק שיטות לביצוע שאילתות SQL ולשינוי נתונים באמצעות הצהרות של שפת טיפול בנתונים (DML). אפשר גם להשתמש ב-bean הזה כדי לגשת אל read API ו-mutation API של Spanner.

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

בקטעים הבאים מוסבר איך לעבוד עם SpannerTemplate ועם SpannerRepository.

קבלת רכיב template bean

משתמשים בהערה @Autowired כדי לקבל אוטומטית רכיב SpannerTemplate. אחרי זה תוכלו להשתמש בSpannerTemplate בכל הכיתה.

בדוגמה הבאה מוצגת מחלקה שמקבלת את ה-bean ומשתמשת בו:

import com.google.cloud.spanner.KeySet;
import com.google.cloud.spanner.Statement;
import com.google.cloud.spring.data.spanner.core.SpannerQueryOptions;
import com.google.cloud.spring.data.spanner.core.SpannerTemplate;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * A quick start code for Spring Data Cloud Spanner. It demonstrates how to use SpannerTemplate to
 * execute DML and SQL queries, save POJOs, and read entities.
 */
@Component
public class SpannerTemplateSample {

  @Autowired
  SpannerTemplate spannerTemplate;

  public void runTemplateExample(Singer singer) {
    // Delete all of the rows in the Singer table.
    this.spannerTemplate.delete(Singer.class, KeySet.all());

    // Insert a singer into the Singers table.
    this.spannerTemplate.insert(singer);

    // Read all of the singers in the Singers table.
    List<Singer> allSingers = this.spannerTemplate
        .query(Singer.class, Statement.of("SELECT * FROM Singers"),
                new SpannerQueryOptions().setAllowPartialRead(true));
  }

}

אפשר להשתמש ב-SpannerTemplate bean כדי להפעיל עסקאות לקריאה בלבד ועסקאות לקריאה ולכתיבה. בנוסף, אפשר להשתמש בהערה @Transactional כדי ליצור טרנזקציות הצהרתיות.

קבלת רכיב Repository Bean

אם משתמשים ב-SpannerRepository, אפשר להשתמש בהערה @Autowired כדי לקבל רכיב bean שמטמיע את הממשק של המאגר. מאגר כולל שיטות להפעלת פונקציות Java כטרנזקציות לקריאה בלבד וטרנזקציות לקריאה וכתיבה. לפעולות ברמה נמוכה יותר, אפשר לקבל את רכיב ה-bean של התבנית שמאגר הנתונים משתמש בו.

בדוגמאות הבאות מוצג הממשק של מאגר ושל מחלקה שמקבלת את ה-bean ומשתמשת בו:

import com.google.cloud.spanner.Key;
import com.google.cloud.spring.data.spanner.repository.SpannerRepository;
import com.google.cloud.spring.data.spanner.repository.query.Query;
import java.util.List;
import org.springframework.data.repository.query.Param;


/**
 * An interface of various Query Methods. The behavior of the queries is defined only by
 * their names, arguments, or annotated SQL strings. The implementation of these functions
 * is generated by Spring Data Cloud Spanner.
 */
public interface SingerRepository extends SpannerRepository<Singer, Key> {
  List<Singer> findByLastName(String lastName);

  int countByFirstName(String firstName);

  int deleteByLastName(String lastName);

  List<Singer> findTop3DistinctByFirstNameAndSingerIdIgnoreCaseOrLastNameOrderByLastNameDesc(
      String firstName, String lastName, long singerId);

  @Query("SELECT * FROM Singers WHERE firstName LIKE '%@fragment';")
  List<Singer> getByQuery(@Param("fragment") String firstNameFragment);
}
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * A quick start code for Spring Data Cloud Spanner.
 * It demonstrates how to use a SpannerRepository to execute read-write queries
 * generated from interface definitions.
 *
 */
@Component
public class SpannerRepositorySample {

  @Autowired
  SingerRepository singerRepository;

  public void runRepositoryExample() {
    List<Singer> lastNameSingers = this.singerRepository.findByLastName("a last name");

    int fistNameCount = this.singerRepository.countByFirstName("a first name");

    int deletedLastNameCount = this.singerRepository.deleteByLastName("a last name");
  }

}

ניהול Spanner

כדי לקבל מידע על מסדי נתונים ב-Spanner, לעדכן סכימה באמצעות הצהרה של שפת הגדרת נתונים (DDL) או לבצע משימות ניהול אחרות, אפשר להשיג רכיב SpannerDatabaseAdminTemplate.

משתמשים בהערה @Autowired כדי לקבל את ה-bean באופן אוטומטי. אחרי זה תוכלו להשתמש בSpannerDatabaseAdminTemplate בכל הכיתה.

בדוגמה הבאה מוצגת מחלקה שמקבלת את ה-bean ומשתמשת בו:

import com.google.cloud.spring.data.spanner.core.admin.SpannerDatabaseAdminTemplate;
import com.google.cloud.spring.data.spanner.core.admin.SpannerSchemaUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * This sample demonstrates how to generate schemas for interleaved tables from POJOs and how to
 * execute DDL.
 */
@Component
public class SpannerSchemaToolsSample {

  @Autowired
  SpannerDatabaseAdminTemplate spannerDatabaseAdminTemplate;

  @Autowired
  SpannerSchemaUtils spannerSchemaUtils;

  /**
   * Creates the Singers table. Also creates the Albums table, because Albums is interleaved with
   * Singers.
   */
  public void createTableIfNotExists() {
    if (!this.spannerDatabaseAdminTemplate.tableExists("Singers")) {
      this.spannerDatabaseAdminTemplate.executeDdlStrings(
          this.spannerSchemaUtils
              .getCreateTableDdlStringsForInterleavedHierarchy(Singer.class),
          true);
    }
  }

  /**
   * Drops both the Singers and Albums tables using just a reference to the Singer entity type ,
   * because they are interleaved.
   */
  public void dropTables() {
    if (this.spannerDatabaseAdminTemplate.tableExists("Singers")) {
      this.spannerDatabaseAdminTemplate.executeDdlStrings(
          this.spannerSchemaUtils.getDropTableDdlStringsForInterleavedHierarchy(Singer.class),
          false);
    }
  }
}

המאמרים הבאים