שילוב של 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:


  
    
      com.google.cloud
      spring-cloud-gcp-dependencies
      3.7.7
      pom
      import
    
    
      org.springframework.boot
      spring-boot-dependencies
      ${spring.boot.version}
      pom
      import
    
  



  
    com.google.cloud
    spring-cloud-gcp-starter-data-spanner
  

צריך גם ליצור חשבון שירות ולהשתמש במפתח של חשבון השירות כדי לבצע אימות באמצעות 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)

המאפיין מציין שנכס מכיל רשימה של שורות שהן interleaved עם השורה הנוכחית.

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

דוגמה: אם לישות Singer יכולות להיות רשומות Album שמשולבות זו בזו כצאצאים, מוסיפים מאפיין List לישות 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 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 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 bean, שמטמיע את SpannerOperations. SpannerTemplate כולל שיטות להרצת שאילתות SQL ולשינוי נתונים באמצעות הצהרות של שפת טיפול בנתונים (DML). אפשר גם להשתמש ב-bean הזה כדי לגשת אל read API ואל mutation API של Spanner.

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

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

קבלת רכיב 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 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 ומשתמשת בו:

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, Key> {
  List findByLastName(String lastName);

  int countByFirstName(String firstName);

  int deleteByLastName(String lastName);

  List findTop3DistinctByFirstNameAndSingerIdIgnoreCaseOrLastNameOrderByLastNameDesc(
      String firstName, String lastName, long singerId);

  @Query("SELECT * FROM Singers WHERE firstName LIKE '%@fragment';")
  List 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 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, לעדכן סכימה באמצעות הצהרה של Data Definition Language‏ (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);
    }
  }
}

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